shape_jit/ffi/call_method/
mod.rs1use crate::context::JITContext;
14use crate::jit_array::JitArray;
15use crate::nan_boxing::*;
16use shape_runtime::context::ExecutionContext;
17use std::collections::HashMap;
18
19pub mod array;
21pub mod duration;
22pub mod number;
23pub mod object;
24pub mod result;
25pub mod signal_builder;
26pub mod string;
27pub mod time;
28
29pub use array::call_array_method;
31pub use duration::call_duration_method;
32pub use number::call_number_method;
33pub use object::call_object_method;
34pub use result::call_result_method;
35pub use signal_builder::call_signalbuilder_method;
36pub use string::call_string_method;
37pub use time::call_time_method;
38
39unsafe fn receiver_type_name(receiver_bits: u64, exec_ctx: &ExecutionContext) -> Option<String> {
49 use crate::ffi::typed_object::jit_typed_object_schema_id;
50
51 if is_number(receiver_bits) {
52 return Some("number".to_string());
53 }
54 if receiver_bits == TAG_BOOL_TRUE || receiver_bits == TAG_BOOL_FALSE {
55 return Some("bool".to_string());
56 }
57 if receiver_bits == TAG_NULL || receiver_bits == TAG_NONE {
58 return None;
59 }
60
61 match heap_kind(receiver_bits) {
62 Some(HK_STRING) => Some("string".to_string()),
63 Some(HK_ARRAY) => Some("Array".to_string()),
64 Some(HK_TYPED_OBJECT) => {
65 let schema_id = jit_typed_object_schema_id(receiver_bits);
67 if schema_id == 0 {
68 return None;
69 }
70 let registry = exec_ctx.type_schema_registry();
71 registry.get_by_id(schema_id).map(|s| s.name.clone())
72 }
73 Some(HK_JIT_OBJECT) => Some("object".to_string()),
74 Some(HK_DURATION) => Some("Duration".to_string()),
75 Some(HK_TIME) => Some("DateTime".to_string()),
76 _ => None,
77 }
78}
79
80unsafe fn find_function_by_name(ctx_ref: &JITContext, ufcs_name: &str) -> Option<usize> {
83 if ctx_ref.function_names_ptr.is_null() || ctx_ref.function_names_len == 0 {
84 return None;
85 }
86 let names = unsafe {
87 std::slice::from_raw_parts(ctx_ref.function_names_ptr, ctx_ref.function_names_len)
88 };
89 for (idx, name) in names.iter().enumerate() {
90 if name == ufcs_name {
91 return Some(idx);
92 }
93 }
94 None
95}
96
97unsafe fn try_call_user_method(
109 ctx: *const JITContext,
110 receiver_bits: u64,
111 method_name: &str,
112 args: &[u64],
113) -> Option<u64> {
114 let ctx_ref = unsafe { &*ctx };
115
116 if ctx_ref.exec_context_ptr.is_null() {
118 return None;
119 }
120 let exec_ctx = unsafe { &*(ctx_ref.exec_context_ptr as *const ExecutionContext) };
121
122 let type_name = unsafe { receiver_type_name(receiver_bits, exec_ctx) }?;
124
125 let ufcs_name = format!("{}::{}", type_name, method_name);
127
128 let func_idx = unsafe { find_function_by_name(ctx_ref, &ufcs_name) }?;
130
131 if ctx_ref.function_table.is_null() || func_idx >= ctx_ref.function_table_len {
133 return None;
134 }
135
136 let raw_fn_ptr = unsafe { *(ctx_ref.function_table as *const *const u8).add(func_idx) };
139 if raw_fn_ptr.is_null() {
140 return None;
141 }
142 let fn_ptr = unsafe { *ctx_ref.function_table.add(func_idx) };
143
144 let ctx_mut = unsafe { &mut *(ctx as *mut JITContext) };
147 ctx_mut.stack[ctx_mut.stack_ptr] = receiver_bits;
148 ctx_mut.stack_ptr += 1;
149 for &arg in args {
150 ctx_mut.stack[ctx_mut.stack_ptr] = arg;
151 ctx_mut.stack_ptr += 1;
152 }
153
154 let _result_code = unsafe { fn_ptr(ctx_mut) };
156
157 if ctx_mut.stack_ptr > 0 {
159 ctx_mut.stack_ptr -= 1;
160 Some(ctx_mut.stack[ctx_mut.stack_ptr])
161 } else {
162 Some(TAG_NULL)
163 }
164}
165
166pub extern "C" fn jit_call_method(ctx: *mut JITContext, stack_count: usize) -> u64 {
174 unsafe {
175 if ctx.is_null() || stack_count < 3 {
176 return TAG_NULL;
177 }
178
179 let ctx_ref = &mut *ctx;
180
181 if ctx_ref.stack_ptr == 0 {
183 return TAG_NULL;
184 }
185 ctx_ref.stack_ptr -= 1;
186 let arg_count_bits = ctx_ref.stack[ctx_ref.stack_ptr];
187 let arg_count = if is_number(arg_count_bits) {
188 unbox_number(arg_count_bits) as usize
189 } else {
190 return TAG_NULL;
191 };
192
193 if ctx_ref.stack_ptr == 0 {
195 return TAG_NULL;
196 }
197 ctx_ref.stack_ptr -= 1;
198 let method_bits = ctx_ref.stack[ctx_ref.stack_ptr];
199 let method_name = if is_heap_kind(method_bits, HK_STRING) {
200 jit_unbox::<String>(method_bits).clone()
201 } else {
202 return method_bits; };
204
205 let mut args = Vec::with_capacity(arg_count);
207 for _ in 0..arg_count {
208 if ctx_ref.stack_ptr == 0 {
209 return TAG_NULL;
210 }
211 ctx_ref.stack_ptr -= 1;
212 args.push(ctx_ref.stack[ctx_ref.stack_ptr]);
213 }
214 args.reverse(); if ctx_ref.stack_ptr == 0 {
218 return TAG_NULL;
219 }
220 ctx_ref.stack_ptr -= 1;
221 let receiver_bits = ctx_ref.stack[ctx_ref.stack_ptr];
222
223 if is_heap_kind(receiver_bits, HK_ARRAY) {
226 match method_name.as_str() {
227 "find" | "findIndex" | "some" | "every" | "filter" | "map" | "count" | "group"
228 | "groupBy" | "reduce" => {
229 if args.is_empty() {
231 return TAG_NULL;
232 }
233 let predicate = args[0]; let working_array_bits = receiver_bits;
236
237 if method_name == "reduce" {
239 let initial = if args.len() > 1 {
240 args[1]
241 } else {
242 box_number(0.0)
243 };
244 ctx_ref.stack[ctx_ref.stack_ptr] = working_array_bits;
246 ctx_ref.stack_ptr += 1;
247 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
248 ctx_ref.stack_ptr += 1;
249 ctx_ref.stack[ctx_ref.stack_ptr] = initial;
250 ctx_ref.stack_ptr += 1;
251 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(3.0);
252 ctx_ref.stack_ptr += 1;
253 return super::control::jit_control_reduce(ctx);
254 }
255
256 ctx_ref.stack[ctx_ref.stack_ptr] = working_array_bits;
258 ctx_ref.stack_ptr += 1;
259 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
261 ctx_ref.stack_ptr += 1;
262 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0);
264 ctx_ref.stack_ptr += 1;
265
266 let result = match method_name.as_str() {
267 "find" => super::control::jit_control_find(ctx),
268 "findIndex" => super::control::jit_control_find_index(ctx),
269 "some" => super::control::jit_control_some(ctx),
270 "every" => super::control::jit_control_every(ctx),
271 "filter" => super::control::jit_control_filter(ctx),
272 "map" => super::control::jit_control_map(ctx),
273 "count" => {
274 let filtered = super::control::jit_control_filter(ctx);
276 if is_heap_kind(filtered, HK_ARRAY) {
277 let arr = jit_unbox::<JitArray>(filtered);
278 return box_number(arr.len() as f64);
279 }
280 box_number(0.0)
281 }
282 "group" | "groupBy" => {
283 let elements = jit_unbox::<JitArray>(working_array_bits);
285
286 let mut groups: HashMap<String, Vec<u64>> = HashMap::new();
287
288 for (index, &value) in elements.iter().enumerate() {
289 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
291 ctx_ref.stack_ptr += 1;
292 ctx_ref.stack[ctx_ref.stack_ptr] = value;
293 ctx_ref.stack_ptr += 1;
294 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(index as f64);
295 ctx_ref.stack_ptr += 1;
296 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0);
297 ctx_ref.stack_ptr += 1;
298
299 let key_result = super::control::jit_call_value(ctx);
300
301 let key = if is_heap_kind(key_result, HK_STRING) {
303 jit_unbox::<String>(key_result).clone()
304 } else if is_number(key_result) {
305 format!("{}", unbox_number(key_result))
306 } else if key_result == TAG_BOOL_TRUE {
307 "true".to_string()
308 } else if key_result == TAG_BOOL_FALSE {
309 "false".to_string()
310 } else {
311 "null".to_string()
312 };
313
314 groups.entry(key).or_default().push(value);
315 }
316
317 let mut obj: HashMap<String, u64> = HashMap::new();
324 for (key, values) in groups {
325 obj.insert(key, jit_box(HK_ARRAY, JitArray::from_vec(values)));
326 }
327 jit_box(HK_JIT_OBJECT, obj)
328 }
329 _ => TAG_NULL,
330 };
331
332 return result;
333 }
334 _ => {}
335 }
336 }
337
338 let builtin_result = if is_ok_tag(receiver_bits) || is_err_tag(receiver_bits) {
341 call_result_method(receiver_bits, &method_name, &args)
342 } else if is_number(receiver_bits) {
343 call_number_method(receiver_bits, &method_name, &args)
344 } else if is_inline_function(receiver_bits) {
345 TAG_NULL } else {
347 match heap_kind(receiver_bits) {
348 Some(HK_ARRAY) => call_array_method(receiver_bits, &method_name, &args),
349 Some(HK_STRING) => call_string_method(receiver_bits, &method_name, &args),
350 Some(HK_JIT_OBJECT) => call_object_method(receiver_bits, &method_name, &args),
351 Some(HK_DURATION) => call_duration_method(receiver_bits, &method_name, &args),
352 Some(HK_COLUMN_REF) => TAG_NULL, Some(HK_TIME) => call_time_method(receiver_bits, &method_name, &args),
354 Some(HK_JIT_SIGNAL_BUILDER) => {
355 call_signalbuilder_method(receiver_bits, &method_name, &args)
356 }
357 _ => TAG_NULL,
358 }
359 };
360
361 if builtin_result == TAG_NULL {
363 if let Some(user_result) = try_call_user_method(ctx, receiver_bits, &method_name, &args)
364 {
365 return user_result;
366 }
367 }
368
369 builtin_result
370 }
371}