go_vm/
dispatcher.rs

1// Copyright 2022 The Goscript Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5use crate::gc::GcContainer;
6use crate::value::*;
7use std::hash::{Hash, Hasher};
8
9/// Dispatcher is used to diapatch Array/Slice calls using the vtable.
10pub(crate) trait Dispatcher {
11    fn typ(&self) -> ValueType;
12
13    fn array_with_size(
14        &self,
15        size: usize,
16        cap: usize,
17        val: &GosValue,
18        gcos: &GcContainer,
19    ) -> GosValue;
20
21    fn array_with_data(&self, data: Vec<GosValue>, gcc: &GcContainer) -> GosValue;
22
23    fn array_copy_semantic(&self, vdata: &ValueData, gcc: &GcContainer) -> ValueData;
24
25    fn slice_copy_semantic(&self, vdata: &ValueData) -> ValueData;
26
27    // you cannot just dispatch the default fn hash, as it makes this trait not object-safe
28    fn array_hash(&self, val: &GosValue, state: &mut dyn Hasher);
29
30    fn array_eq(&self, a: &ValueData, b: &ValueData) -> bool;
31
32    fn array_cmp(&self, a: &ValueData, b: &ValueData) -> std::cmp::Ordering;
33
34    fn array_get_vec(&self, val: &GosValue) -> Vec<GosValue>;
35
36    fn slice_get_vec(&self, val: &GosValue) -> Option<Vec<GosValue>>;
37
38    fn array_len(&self, val: &GosValue) -> usize;
39
40    fn slice_slice(
41        &self,
42        slice: &GosValue,
43        begin: isize,
44        end: isize,
45        max: isize,
46    ) -> RuntimeResult<GosValue>;
47
48    fn slice_array(&self, arr: GosValue, begin: isize, end: isize) -> RuntimeResult<GosValue>;
49
50    fn slice_append(
51        &self,
52        this: GosValue,
53        other: GosValue,
54        gcc: &GcContainer,
55    ) -> RuntimeResult<GosValue>;
56
57    fn slice_copy_from(&self, this: GosValue, other: GosValue) -> usize;
58
59    fn array_get(&self, from: &GosValue, i: usize) -> RuntimeResult<GosValue>;
60
61    fn array_set(&self, to: &GosValue, val: &GosValue, i: usize) -> RuntimeResult<()>;
62
63    fn slice_get(&self, from: &GosValue, i: usize) -> RuntimeResult<GosValue>;
64
65    fn slice_set(&self, to: &GosValue, val: &GosValue, i: usize) -> RuntimeResult<()>;
66
67    fn array_slice_iter(&self, val: &GosValue) -> RuntimeResult<SliceEnumIter<'static, AnyElem>>;
68
69    fn array_slice_next(
70        &self,
71        iter: &mut SliceEnumIter<'static, AnyElem>,
72    ) -> Option<(usize, GosValue)>;
73
74    fn slice_swap(&self, slice: &GosValue, i: usize, j: usize) -> RuntimeResult<()>;
75}
76
77/// https://users.rust-lang.org/t/workaround-for-hash-trait-not-being-object-safe/53332/5
78pub(crate) trait DynHash {
79    fn dyn_hash(&self, state: &mut dyn Hasher);
80}
81
82impl<H: Hash + ?Sized> DynHash for H {
83    fn dyn_hash(&self, mut state: &mut dyn Hasher) {
84        self.hash(&mut state);
85    }
86}
87
88macro_rules! define_dispatcher {
89    ($dispatcher:tt, $elem:ty) => {
90        pub(crate) struct $dispatcher {
91            typ: ValueType,
92        }
93
94        impl $dispatcher {
95            pub(crate) fn new(t: ValueType) -> $dispatcher {
96                $dispatcher { typ: t }
97            }
98        }
99
100        impl Dispatcher for $dispatcher {
101            fn typ(&self) -> ValueType {
102                self.typ
103            }
104
105            fn array_with_size(
106                &self,
107                size: usize,
108                cap: usize,
109                val: &GosValue,
110                gcc: &GcContainer,
111            ) -> GosValue {
112                GosValue::new_array(
113                    ArrayObj::<$elem>::with_size(size, cap, val, gcc),
114                    self.typ,
115                    gcc,
116                )
117            }
118
119            #[inline]
120            fn array_with_data(&self, data: Vec<GosValue>, gcc: &GcContainer) -> GosValue {
121                GosValue::new_array(ArrayObj::<$elem>::with_data(data), self.typ, gcc)
122            }
123
124            #[inline]
125            fn array_copy_semantic(&self, vdata: &ValueData, gcc: &GcContainer) -> ValueData {
126                ValueData::new_array::<$elem>(vdata.as_array::<$elem>().0.clone(), gcc)
127            }
128
129            #[inline]
130            fn slice_copy_semantic(&self, vdata: &ValueData) -> ValueData {
131                match vdata.as_slice::<$elem>() {
132                    Some(s) => ValueData::new_slice(s.0.clone()),
133                    None => ValueData::new_nil(ValueType::Slice),
134                }
135            }
136
137            #[inline]
138            fn array_hash(&self, val: &GosValue, state: &mut dyn Hasher) {
139                val.as_array::<$elem>().0.dyn_hash(state);
140            }
141
142            #[inline]
143            fn array_eq(&self, a: &ValueData, b: &ValueData) -> bool {
144                a.as_array::<$elem>().0 == b.as_array::<$elem>().0
145            }
146
147            #[inline]
148            fn array_cmp(&self, a: &ValueData, b: &ValueData) -> std::cmp::Ordering {
149                a.as_array::<$elem>().0.cmp(&b.as_array::<$elem>().0)
150            }
151
152            fn array_get_vec(&self, val: &GosValue) -> Vec<GosValue> {
153                val.as_array::<$elem>()
154                    .0
155                    .as_rust_slice()
156                    .iter()
157                    .map(|x| x.clone().into_value(val.t_elem()))
158                    .collect()
159            }
160
161            fn slice_get_vec(&self, val: &GosValue) -> Option<Vec<GosValue>> {
162                val.as_slice::<$elem>().map(|x| {
163                    x.0.as_rust_slice()
164                        .iter()
165                        .map(|y| y.clone().into_value(val.t_elem()))
166                        .collect()
167                })
168            }
169
170            #[inline]
171            fn array_len(&self, val: &GosValue) -> usize {
172                val.as_array::<$elem>().0.len()
173            }
174
175            #[inline]
176            fn slice_slice(
177                &self,
178                slice: &GosValue,
179                begin: isize,
180                end: isize,
181                max: isize,
182            ) -> RuntimeResult<GosValue> {
183                Ok(GosValue::new_slice(
184                    slice
185                        .as_non_nil_slice::<$elem>()?
186                        .0
187                        .slice(begin, end, max)?,
188                    slice.t_elem,
189                ))
190            }
191
192            #[inline]
193            fn slice_array(
194                &self,
195                arr: GosValue,
196                begin: isize,
197                end: isize,
198            ) -> RuntimeResult<GosValue> {
199                Ok(GosValue::new_slice::<$elem>(
200                    SliceObj::with_array(arr, begin, end)?,
201                    self.typ,
202                ))
203            }
204
205            #[inline]
206            fn slice_append(
207                &self,
208                this: GosValue,
209                other: GosValue,
210                gcc: &GcContainer,
211            ) -> RuntimeResult<GosValue> {
212                let a = this.as_slice::<$elem>();
213                let b = other.as_slice::<$elem>();
214                match b {
215                    Some(y) => match a {
216                        Some(x) => {
217                            let mut to = x.0.clone();
218                            to.append(&y.0);
219                            Ok(GosValue::new_slice(to, other.t_elem()))
220                        }
221                        None => {
222                            let data = y.0.as_rust_slice().to_vec();
223                            let arr = ArrayObj::<$elem>::with_raw_data(data);
224                            let slice = SliceObj::<$elem>::with_array(
225                                GosValue::new_array(arr, other.t_elem(), gcc),
226                                0,
227                                -1,
228                            )?;
229                            Ok(GosValue::new_slice(slice, other.t_elem()))
230                        }
231                    },
232                    None => Ok(this),
233                }
234            }
235
236            #[inline]
237            fn slice_copy_from(&self, this: GosValue, other: GosValue) -> usize {
238                let a = this.as_slice::<$elem>();
239                let b = other.as_slice::<$elem>();
240                match (a, b) {
241                    (Some(x), Some(y)) => x.0.copy_from(&y.0),
242                    _ => 0,
243                }
244            }
245
246            #[inline]
247            fn array_get(&self, from: &GosValue, i: usize) -> RuntimeResult<GosValue> {
248                from.as_array::<$elem>().0.get(i, self.typ)
249            }
250
251            #[inline]
252            fn array_set(&self, to: &GosValue, val: &GosValue, i: usize) -> RuntimeResult<()> {
253                to.as_array::<$elem>().0.set(i, val)
254            }
255
256            #[inline]
257            fn slice_get(&self, from: &GosValue, i: usize) -> RuntimeResult<GosValue> {
258                from.as_non_nil_slice::<$elem>()?.0.get(i, self.typ)
259            }
260
261            #[inline]
262            fn slice_set(&self, to: &GosValue, val: &GosValue, i: usize) -> RuntimeResult<()> {
263                to.as_non_nil_slice::<$elem>()?.0.set(i, val)
264            }
265
266            #[inline]
267            fn array_slice_iter(
268                &self,
269                val: &GosValue,
270            ) -> RuntimeResult<SliceEnumIter<'static, AnyElem>> {
271                let rust_slice = match val.typ() {
272                    ValueType::Slice => val.as_non_nil_slice::<$elem>()?.0.as_rust_slice(),
273                    ValueType::Array => val.as_array::<$elem>().0.as_rust_slice(),
274                    _ => unreachable!(),
275                };
276                Ok(unsafe { std::mem::transmute(rust_slice.iter().enumerate()) })
277            }
278
279            #[inline]
280            fn array_slice_next(
281                &self,
282                iter: &mut SliceEnumIter<'static, AnyElem>,
283            ) -> Option<(usize, GosValue)> {
284                let iter: &mut SliceEnumIter<'static, $elem> = unsafe { std::mem::transmute(iter) };
285                match iter.next() {
286                    Some((i, v)) => Some((i, v.clone().into_value(self.typ))),
287                    None => None,
288                }
289            }
290
291            #[inline]
292            fn slice_swap(&self, slice: &GosValue, i: usize, j: usize) -> RuntimeResult<()> {
293                slice.as_non_nil_slice::<$elem>()?.0.swap(i, j)
294            }
295        }
296    };
297}
298
299#[derive(Clone, Copy)]
300pub(crate) enum ElemType {
301    ElemType8,
302    ElemType16,
303    ElemType32,
304    ElemType64,
305    ElemTypeWord,
306    ElemTypeGos,
307}
308
309pub(crate) struct ArrCaller {
310    disp_array: [Box<dyn Dispatcher>; ValueType::Channel as usize + 1],
311}
312
313impl ArrCaller {
314    pub fn new() -> ArrCaller {
315        ArrCaller {
316            disp_array: [
317                Box::new(DispatcherGos::new(ValueType::Void)),
318                Box::new(Dispatcher8::new(ValueType::Bool)),
319                Box::new(DispatcherWord::new(ValueType::Int)),
320                Box::new(Dispatcher8::new(ValueType::Int8)),
321                Box::new(Dispatcher16::new(ValueType::Int16)),
322                Box::new(Dispatcher32::new(ValueType::Int32)),
323                Box::new(Dispatcher64::new(ValueType::Int64)),
324                Box::new(DispatcherWord::new(ValueType::Uint)),
325                Box::new(DispatcherWord::new(ValueType::UintPtr)),
326                Box::new(Dispatcher8::new(ValueType::Uint8)),
327                Box::new(Dispatcher16::new(ValueType::Uint16)),
328                Box::new(Dispatcher32::new(ValueType::Uint32)),
329                Box::new(Dispatcher64::new(ValueType::Uint64)),
330                Box::new(Dispatcher32::new(ValueType::Float32)),
331                Box::new(Dispatcher64::new(ValueType::Float64)),
332                Box::new(Dispatcher64::new(ValueType::Complex64)),
333                Box::new(DispatcherWord::new(ValueType::Function)),
334                Box::new(DispatcherWord::new(ValueType::Package)),
335                Box::new(DispatcherGos::new(ValueType::Metadata)),
336                Box::new(DispatcherGos::new(ValueType::Complex128)),
337                Box::new(DispatcherGos::new(ValueType::String)),
338                Box::new(DispatcherGos::new(ValueType::Array)),
339                Box::new(DispatcherGos::new(ValueType::Struct)),
340                Box::new(DispatcherGos::new(ValueType::Pointer)),
341                Box::new(DispatcherGos::new(ValueType::UnsafePtr)),
342                Box::new(DispatcherGos::new(ValueType::Closure)),
343                Box::new(DispatcherGos::new(ValueType::Slice)),
344                Box::new(DispatcherGos::new(ValueType::Map)),
345                Box::new(DispatcherGos::new(ValueType::Interface)),
346                Box::new(DispatcherGos::new(ValueType::Channel)),
347            ],
348        }
349    }
350
351    #[inline]
352    pub fn get(&self, t: ValueType) -> &Box<dyn Dispatcher> {
353        &self.disp_array[t as usize]
354    }
355
356    #[inline]
357    pub fn get_slow(t: ValueType) -> Box<dyn Dispatcher> {
358        match t {
359            ValueType::Int8 | ValueType::Uint8 => Box::new(Dispatcher8::new(t)),
360            ValueType::Int16 | ValueType::Uint16 => Box::new(Dispatcher16::new(t)),
361            ValueType::Int32 | ValueType::Uint32 | ValueType::Float32 => {
362                Box::new(Dispatcher32::new(t))
363            }
364            ValueType::Int64 | ValueType::Uint64 | ValueType::Float64 | ValueType::Complex64 => {
365                Box::new(Dispatcher64::new(t))
366            }
367            ValueType::Int
368            | ValueType::Uint
369            | ValueType::UintPtr
370            | ValueType::Function
371            | ValueType::Package => Box::new(Dispatcher64::new(t)),
372            _ => Box::new(DispatcherGos::new(t)),
373        }
374    }
375
376    #[inline]
377    pub fn get_elem_type(t: ValueType) -> ElemType {
378        const ELEM_TYPES: [ElemType; ValueType::Channel as usize + 1] = [
379            ElemType::ElemTypeGos,
380            ElemType::ElemType8,
381            ElemType::ElemTypeWord,
382            ElemType::ElemType8,
383            ElemType::ElemType16,
384            ElemType::ElemType32,
385            ElemType::ElemType64,
386            ElemType::ElemTypeWord,
387            ElemType::ElemTypeWord,
388            ElemType::ElemType8,
389            ElemType::ElemType16,
390            ElemType::ElemType32,
391            ElemType::ElemType64,
392            ElemType::ElemType32,
393            ElemType::ElemType64,
394            ElemType::ElemType64,
395            ElemType::ElemTypeWord,
396            ElemType::ElemTypeWord,
397            ElemType::ElemTypeGos,
398            ElemType::ElemTypeGos,
399            ElemType::ElemTypeGos,
400            ElemType::ElemTypeGos,
401            ElemType::ElemTypeGos,
402            ElemType::ElemTypeGos,
403            ElemType::ElemTypeGos,
404            ElemType::ElemTypeGos,
405            ElemType::ElemTypeGos,
406            ElemType::ElemTypeGos,
407            ElemType::ElemTypeGos,
408            ElemType::ElemTypeGos,
409        ];
410        ELEM_TYPES[t as usize]
411    }
412
413    // #[inline]
414    // pub fn get_static(t: ValueType) -> &'static Box<dyn Dispatcher> {
415    //     static mut DISPATCHERS: Option<ArrCaller> = None;
416    //     unsafe {
417    //         match &DISPATCHERS {
418    //             Some(d) => &d.disp_array[t as usize],
419    //             None => {
420    //                 DISPATCHERS = Some(ArrCaller::new());
421    //                 &DISPATCHERS.as_ref().unwrap().disp_array[t as usize]
422    //             }
423    //         }
424    //     }
425    // }
426}