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 let mut args = Vec::with_capacity(arg_count);
206 for _ in 0..arg_count {
207 if ctx_ref.stack_ptr == 0 {
208 return TAG_NULL;
209 }
210 ctx_ref.stack_ptr -= 1;
211 args.push(ctx_ref.stack[ctx_ref.stack_ptr]);
212 }
213 args.reverse(); if ctx_ref.stack_ptr == 0 {
217 return TAG_NULL;
218 }
219 ctx_ref.stack_ptr -= 1;
220 let receiver_bits = ctx_ref.stack[ctx_ref.stack_ptr];
221
222 if is_heap_kind(receiver_bits, HK_ARRAY) {
225 match method_name.as_str() {
226 "find" | "findIndex" | "some" | "every" | "filter" | "map" | "count" | "group"
227 | "groupBy" | "reduce" => {
228 if args.is_empty() {
230 return TAG_NULL;
231 }
232 let predicate = args[0]; let working_array_bits = receiver_bits;
235
236 if method_name == "reduce" {
238 let initial = if args.len() > 1 {
239 args[1]
240 } else {
241 box_number(0.0)
242 };
243 ctx_ref.stack[ctx_ref.stack_ptr] = working_array_bits;
245 ctx_ref.stack_ptr += 1;
246 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
247 ctx_ref.stack_ptr += 1;
248 ctx_ref.stack[ctx_ref.stack_ptr] = initial;
249 ctx_ref.stack_ptr += 1;
250 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(3.0);
251 ctx_ref.stack_ptr += 1;
252 return super::control::jit_control_reduce(ctx);
253 }
254
255 ctx_ref.stack[ctx_ref.stack_ptr] = working_array_bits;
257 ctx_ref.stack_ptr += 1;
258 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
260 ctx_ref.stack_ptr += 1;
261 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0);
263 ctx_ref.stack_ptr += 1;
264
265 let result = match method_name.as_str() {
266 "find" => super::control::jit_control_find(ctx),
267 "findIndex" => super::control::jit_control_find_index(ctx),
268 "some" => super::control::jit_control_some(ctx),
269 "every" => super::control::jit_control_every(ctx),
270 "filter" => super::control::jit_control_filter(ctx),
271 "map" => super::control::jit_control_map(ctx),
272 "count" => {
273 let filtered = super::control::jit_control_filter(ctx);
275 if is_heap_kind(filtered, HK_ARRAY) {
276 let arr = jit_unbox::<JitArray>(filtered);
277 return box_number(arr.len() as f64);
278 }
279 box_number(0.0)
280 }
281 "group" | "groupBy" => {
282 let elements = jit_unbox::<JitArray>(working_array_bits);
284
285 let mut groups: HashMap<String, Vec<u64>> = HashMap::new();
286
287 for (index, &value) in elements.iter().enumerate() {
288 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
290 ctx_ref.stack_ptr += 1;
291 ctx_ref.stack[ctx_ref.stack_ptr] = value;
292 ctx_ref.stack_ptr += 1;
293 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(index as f64);
294 ctx_ref.stack_ptr += 1;
295 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0);
296 ctx_ref.stack_ptr += 1;
297
298 let key_result = super::control::jit_call_value(ctx);
299
300 let key = if is_heap_kind(key_result, HK_STRING) {
302 jit_unbox::<String>(key_result).clone()
303 } else if is_number(key_result) {
304 format!("{}", unbox_number(key_result))
305 } else if key_result == TAG_BOOL_TRUE {
306 "true".to_string()
307 } else if key_result == TAG_BOOL_FALSE {
308 "false".to_string()
309 } else {
310 "null".to_string()
311 };
312
313 groups.entry(key).or_default().push(value);
314 }
315
316 let mut obj: HashMap<String, u64> = HashMap::new();
323 for (key, values) in groups {
324 obj.insert(key, jit_box(HK_ARRAY, JitArray::from_vec(values)));
325 }
326 jit_box(HK_JIT_OBJECT, obj)
327 }
328 _ => TAG_NULL,
329 };
330
331 return result;
332 }
333 _ => {}
334 }
335 }
336
337 let builtin_result = if is_ok_tag(receiver_bits) || is_err_tag(receiver_bits) {
340 call_result_method(receiver_bits, &method_name, &args)
341 } else if is_number(receiver_bits) {
342 call_number_method(receiver_bits, &method_name, &args)
343 } else if is_inline_function(receiver_bits) {
344 TAG_NULL } else {
346 match heap_kind(receiver_bits) {
347 Some(HK_ARRAY) => call_array_method(receiver_bits, &method_name, &args),
348 Some(HK_STRING) => call_string_method(receiver_bits, &method_name, &args),
349 Some(HK_JIT_OBJECT) => call_object_method(receiver_bits, &method_name, &args),
350 Some(HK_DURATION) => call_duration_method(receiver_bits, &method_name, &args),
351 Some(HK_COLUMN_REF) => TAG_NULL, Some(HK_TIME) => call_time_method(receiver_bits, &method_name, &args),
353 Some(HK_JIT_SIGNAL_BUILDER) => {
354 call_signalbuilder_method(receiver_bits, &method_name, &args)
355 }
356 _ => TAG_NULL,
357 }
358 };
359
360 if builtin_result == TAG_NULL {
362 if let Some(user_result) = try_call_user_method(ctx, receiver_bits, &method_name, &args)
363 {
364 return user_result;
365 }
366 }
367
368 builtin_result
369 }
370}