Skip to content

Commit e965779

Browse files
committed
update jit
1 parent d575a66 commit e965779

18 files changed

Lines changed: 2444 additions & 2193 deletions

File tree

build.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,11 @@ fn write_core_package_index() -> Result<(), String> {
137137
}
138138

139139
fn write_reg_vm_runtime_intrinsics() -> Result<(), String> {
140-
println!("cargo:rerun-if-changed=src/reg_vm.rs");
140+
println!("cargo:rerun-if-changed=src/reg_vm/mod.rs");
141141
println!("cargo:rerun-if-changed=src/runtime_abi.rs");
142142

143143
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("manifest dir"));
144-
let source_path = manifest_dir.join("src/reg_vm.rs");
144+
let source_path = manifest_dir.join("src/reg_vm/mod.rs");
145145
let source = fs::read_to_string(&source_path)
146146
.map_err(|error| format!("failed to read {}: {error}", source_path.display()))?;
147147
let resolver_signatures = collect_reg_vm_resolver_signatures(&source)?;

docs/jit-todo.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,23 @@ don't pull in the codegen dependency). Enable with `--features native-jit`.
9898
in native code — the function **bails to the interpreter** (the single source of
9999
truth) instead, which is gap-free because the compiled subset is side-effect-free.
100100
- [x] `VmValue` ABI for native code: `Int`/`Bool` unbox into `i64` registers,
101-
the result boxes back as `Int`. Native runs only when every argument is an
102-
`Int`, so all registers are statically `i64` (`Float`/heap stay on fallback).
101+
the result boxes back as `Int` or `Float`. Native runs only when every argument
102+
is an `Int`, so parameters are statically `i64`; heap values stay on fallback.
103+
- [x] **Float support** (`f64` register class): the arithmetic/compare opcodes are
104+
type-polymorphic, lowering to `iadd`/`fadd`, `icmp`/`fcmp`, etc. by per-register
105+
type (the IR carries `reg_types`). Float-computing functions (e.g. the float
106+
differential's `compute()`) compile natively. Verified 5-way; **~93× faster**
107+
than the interpreter on a float kernel.
108+
- [x] **Inlining of straight-line leaf calls** (toward Phase-3 speculative
109+
inlining): a numeric function that calls small pure helpers is made
110+
native-eligible by splicing each branch-free leaf callee into the caller's
111+
register window (`native_inline_leaf_calls`), so the call disappears. Verified
112+
5-way (`backends_agree_on_cross_function_calls` inlines its helpers); **~135×
113+
faster** on a call-in-loop numeric kernel that previously fell back.
114+
- [x] **Faster VM value representation** (`vm_value::FnvHasher`): struct/variant
115+
fields and `Map` values use an FNV-1a hasher instead of SipHash (the VM's maps
116+
are never adversarial), speeding the field/key hashing the interpreter does
117+
constantly (~5% on map-insert; broad, applies under every backend).
103118
- [x] Tiering: a per-function hot-call counter (`tier_up_threshold`) defers
104119
native compilation until a function is hot. (OSR is not applicable to this
105120
method-at-a-time JIT — whole functions are (re)compiled and re-entered fresh;

src/analyzer.rs

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::text_util::{split_top_level_type_args, type_arg_names, type_root_name};
12
use std::collections::{HashMap, HashSet};
23

34
use crate::checks;
@@ -4611,24 +4612,6 @@ fn generic_namespace_args(namespace: &str) -> Option<(&str, Vec<&str>)> {
46114612
Some((root, split_top_level_type_args(args)))
46124613
}
46134614

4614-
fn split_top_level_type_args(args: &str) -> Vec<&str> {
4615-
let mut result = Vec::new();
4616-
let mut depth = 0usize;
4617-
let mut start = 0usize;
4618-
for (index, ch) in args.char_indices() {
4619-
match ch {
4620-
'<' => depth += 1,
4621-
'>' => depth = depth.saturating_sub(1),
4622-
',' if depth == 0 => {
4623-
result.push(args[start..index].trim());
4624-
start = index + 1;
4625-
}
4626-
_ => {}
4627-
}
4628-
}
4629-
result.push(args[start..].trim());
4630-
result
4631-
}
46324615

46334616
fn effect_name(effect: &EffectDecl) -> &str {
46344617
match effect {
@@ -5866,43 +5849,7 @@ fn builtin_value_type_name(name: &str) -> Option<&'static str> {
58665849
}
58675850
}
58685851

5869-
fn type_root_name(type_name: &str) -> &str {
5870-
let type_name = type_name
5871-
.trim()
5872-
.strip_prefix("fresh ")
5873-
.unwrap_or(type_name.trim());
5874-
type_name
5875-
.split_once('<')
5876-
.map_or(type_name, |(root, _)| root)
5877-
}
58785852

5879-
fn type_arg_names(type_name: &str) -> Option<Vec<&str>> {
5880-
let start = type_name.find('<')?;
5881-
let end = type_name.rfind('>')?;
5882-
if end <= start {
5883-
return None;
5884-
}
5885-
let inner = &type_name[start + 1..end];
5886-
let mut args = Vec::new();
5887-
let mut depth = 0usize;
5888-
let mut part_start = 0usize;
5889-
for (index, ch) in inner.char_indices() {
5890-
match ch {
5891-
'<' => depth += 1,
5892-
'>' => depth = depth.saturating_sub(1),
5893-
',' if depth == 0 => {
5894-
args.push(inner[part_start..index].trim());
5895-
part_start = index + ch.len_utf8();
5896-
}
5897-
_ => {}
5898-
}
5899-
}
5900-
let tail = inner[part_start..].trim();
5901-
if !tail.is_empty() {
5902-
args.push(tail);
5903-
}
5904-
Some(args)
5905-
}
59065853

59075854
fn constructor_pattern_is_irrefutable(pattern: &MatchPattern) -> bool {
59085855
match pattern {

src/checks/body.rs

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::text_util::{split_top_level_type_args, type_arg_names, type_root_name};
12
use std::collections::{HashMap, HashSet};
23

34
use crate::analyzer::Analyzer;
@@ -6417,26 +6418,6 @@ fn strip_fresh_type(type_name: &str) -> &str {
64176418
.unwrap_or(type_name)
64186419
}
64196420

6420-
fn split_top_level_type_args(args: &str) -> Vec<&str> {
6421-
let mut parts = Vec::new();
6422-
let mut start = 0usize;
6423-
let mut depth = 0usize;
6424-
for (index, ch) in args.char_indices() {
6425-
match ch {
6426-
'<' => depth += 1,
6427-
'>' => depth = depth.saturating_sub(1),
6428-
',' if depth == 0 => {
6429-
parts.push(args[start..index].trim());
6430-
start = index + ch.len_utf8();
6431-
}
6432-
_ => {}
6433-
}
6434-
}
6435-
if start < args.len() {
6436-
parts.push(args[start..].trim());
6437-
}
6438-
parts
6439-
}
64406421

64416422
fn check_resource_pool_lease_stmt(analyzer: &mut Analyzer<'_>, statement: &HirStmt) {
64426423
match statement {
@@ -6714,43 +6695,7 @@ fn is_resource_pool_constructor(callee: &Callee) -> bool {
67146695
is_resource_pool_infallible_constructor(callee) || is_resource_pool_fallible_constructor(callee)
67156696
}
67166697

6717-
fn type_root_name(type_name: &str) -> &str {
6718-
let type_name = type_name
6719-
.trim()
6720-
.strip_prefix("fresh ")
6721-
.unwrap_or(type_name.trim());
6722-
type_name
6723-
.split_once('<')
6724-
.map_or(type_name, |(root, _)| root)
6725-
}
67266698

6727-
fn type_arg_names(type_name: &str) -> Option<Vec<&str>> {
6728-
let start = type_name.find('<')?;
6729-
let end = type_name.rfind('>')?;
6730-
if end <= start {
6731-
return None;
6732-
}
6733-
let inner = &type_name[start + 1..end];
6734-
let mut args = Vec::new();
6735-
let mut depth = 0usize;
6736-
let mut part_start = 0usize;
6737-
for (index, ch) in inner.char_indices() {
6738-
match ch {
6739-
'<' => depth += 1,
6740-
'>' => depth = depth.saturating_sub(1),
6741-
',' if depth == 0 => {
6742-
args.push(inner[part_start..index].trim());
6743-
part_start = index + ch.len_utf8();
6744-
}
6745-
_ => {}
6746-
}
6747-
}
6748-
let tail = inner[part_start..].trim();
6749-
if !tail.is_empty() {
6750-
args.push(tail);
6751-
}
6752-
Some(args)
6753-
}
67546699

67556700
fn is_resource_pool_type(type_name: &str) -> bool {
67566701
type_root_name(type_name) == "ResourcePool"

src/checks/calls.rs

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::text_util::{split_top_level_type_args, type_arg_names, type_root_name};
12
use std::collections::{HashMap, HashSet};
23

34
use crate::analyzer::Analyzer;
@@ -4588,12 +4589,6 @@ pub(crate) fn unresolved_generic_type(type_name: &str) -> bool {
45884589
.any(|param_type| unresolved_generic_type(param_type))
45894590
}
45904591

4591-
fn type_arg_names(type_name: &str) -> Option<Vec<&str>> {
4592-
let inner = type_name
4593-
.split_once('<')
4594-
.and_then(|(_, rest)| rest.strip_suffix('>'))?;
4595-
Some(split_top_level_type_args(inner))
4596-
}
45974592

45984593
fn builtin_generic_type_params(root: &str) -> Option<Vec<&'static str>> {
45994594
match root {
@@ -4606,36 +4601,7 @@ fn builtin_generic_type_params(root: &str) -> Option<Vec<&'static str>> {
46064601
}
46074602
}
46084603

4609-
fn split_top_level_type_args(args: &str) -> Vec<&str> {
4610-
let mut parts = Vec::new();
4611-
let mut start = 0usize;
4612-
let mut depth = 0usize;
4613-
for (index, ch) in args.char_indices() {
4614-
match ch {
4615-
'<' => depth += 1,
4616-
'>' => depth = depth.saturating_sub(1),
4617-
',' if depth == 0 => {
4618-
parts.push(args[start..index].trim());
4619-
start = index + ch.len_utf8();
4620-
}
4621-
_ => {}
4622-
}
4623-
}
4624-
if start < args.len() {
4625-
parts.push(args[start..].trim());
4626-
}
4627-
parts
4628-
}
46294604

4630-
fn type_root_name(type_name: &str) -> &str {
4631-
let type_name = type_name
4632-
.trim()
4633-
.strip_prefix("fresh ")
4634-
.unwrap_or(type_name.trim());
4635-
type_name
4636-
.split_once('<')
4637-
.map_or(type_name, |(root, _)| root)
4638-
}
46394605

46404606
fn hir_expr_span(expr: &HirExpr) -> &Span {
46414607
match expr {

src/checks/forbidden.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::text_util::type_root_name;
12
use crate::analyzer::Analyzer;
23
use crate::diagnostic::{Diagnostic, code};
34
use crate::hir::{HirBlock, HirExpr, HirStmt};
@@ -534,6 +535,3 @@ fn is_numeric_type(type_name: &str) -> bool {
534535
)
535536
}
536537

537-
fn type_root_name(type_name: &str) -> &str {
538-
type_name.split('<').next().unwrap_or(type_name)
539-
}

src/checks/local.rs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::text_util::split_top_level_type_args;
12
use std::collections::{HashMap, HashSet, VecDeque};
23

34
use crate::diagnostic::Span;
@@ -2468,26 +2469,6 @@ fn is_fresh_match_scrutinee(expr: &HirExpr) -> bool {
24682469
}
24692470
}
24702471

2471-
fn split_top_level_type_args(args: &str) -> Vec<&str> {
2472-
let mut parts = Vec::new();
2473-
let mut start = 0usize;
2474-
let mut depth = 0usize;
2475-
for (index, ch) in args.char_indices() {
2476-
match ch {
2477-
'<' => depth += 1,
2478-
'>' => depth = depth.saturating_sub(1),
2479-
',' if depth == 0 => {
2480-
parts.push(args[start..index].trim());
2481-
start = index + ch.len_utf8();
2482-
}
2483-
_ => {}
2484-
}
2485-
}
2486-
if start < args.len() {
2487-
parts.push(args[start..].trim());
2488-
}
2489-
parts
2490-
}
24912472

24922473
fn strip_fresh_type(type_name: &str) -> &str {
24932474
type_name

src/hir.rs

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::text_util::{split_top_level_type_args, type_arg_names, type_root_name};
12
use std::collections::{HashMap, HashSet};
23

34
use crate::diagnostic::Span;
@@ -2784,12 +2785,6 @@ fn substitute_type_params(type_name: &str, substitutions: &HashMap<String, Strin
27842785
format!("{root}<{args}>")
27852786
}
27862787

2787-
fn type_arg_names(type_name: &str) -> Option<Vec<&str>> {
2788-
let inner = type_name
2789-
.split_once('<')
2790-
.and_then(|(_, rest)| rest.strip_suffix('>'))?;
2791-
Some(split_top_level_type_args(inner))
2792-
}
27932788

27942789
fn builtin_generic_type_params(root: &str) -> Option<Vec<&'static str>> {
27952790
match root {
@@ -3015,26 +3010,6 @@ fn collect_struct_pattern_binding_types(
30153010
bindings
30163011
}
30173012

3018-
fn split_top_level_type_args(args: &str) -> Vec<&str> {
3019-
let mut parts = Vec::new();
3020-
let mut start = 0usize;
3021-
let mut depth = 0usize;
3022-
for (index, ch) in args.char_indices() {
3023-
match ch {
3024-
'<' => depth += 1,
3025-
'>' => depth = depth.saturating_sub(1),
3026-
',' if depth == 0 => {
3027-
parts.push(args[start..index].trim());
3028-
start = index + ch.len_utf8();
3029-
}
3030-
_ => {}
3031-
}
3032-
}
3033-
if start < args.len() {
3034-
parts.push(args[start..].trim());
3035-
}
3036-
parts
3037-
}
30383013

30393014
fn classify_block_return_expr(
30403015
hir: &Hir,
@@ -3291,11 +3266,6 @@ fn type_ref_name(ty: &TypeRef) -> String {
32913266
}
32923267
}
32933268

3294-
fn type_root_name(type_name: &str) -> &str {
3295-
strip_fresh_type(type_name)
3296-
.split_once('<')
3297-
.map_or(strip_fresh_type(type_name), |(root, _)| root)
3298-
}
32993269

33003270
fn strip_fresh_type(type_name: &str) -> &str {
33013271
type_name

0 commit comments

Comments
 (0)