From 2ae9fab45891429a187fb6e6a8836bad8e81a9a6 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Mon, 8 Jun 2026 07:37:46 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=8B=86=E5=88=86=E7=BB=91?= =?UTF-8?q?=E5=AE=9A=E5=87=BD=E6=95=B0=E4=B8=8E=E5=B0=81=E8=A3=85=E5=AE=8F?= =?UTF-8?q?=E4=BB=A5=E7=AE=80=E5=8C=96=E6=A8=A1=E5=9D=97=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_kernel/src/builtin.rs | 8 + crates/oxide_vm/src/bindings/bind_array.rs | 45 + crates/oxide_vm/src/bindings/bind_boolean.rs | 48 + crates/oxide_vm/src/bindings/bind_date.rs | 351 ++++ crates/oxide_vm/src/bindings/bind_error.rs | 37 + crates/oxide_vm/src/bindings/bind_function.rs | 17 + crates/oxide_vm/src/bindings/bind_json.rs | 38 + crates/oxide_vm/src/bindings/bind_map.rs | 82 + crates/oxide_vm/src/bindings/bind_math.rs | 84 + crates/oxide_vm/src/bindings/bind_number.rs | 62 + crates/oxide_vm/src/bindings/bind_object.rs | 39 + crates/oxide_vm/src/bindings/bind_set.rs | 73 + crates/oxide_vm/src/bindings/bind_string.rs | 44 + crates/oxide_vm/src/bindings/mod.rs | 63 + crates/oxide_vm/src/dispatch/arithmetic.rs | 1 + crates/oxide_vm/src/dispatch/call.rs | 57 + crates/oxide_vm/src/dispatch/comparison.rs | 1 + crates/oxide_vm/src/dispatch/control_flow.rs | 1 + crates/oxide_vm/src/dispatch/exception.rs | 1 + crates/oxide_vm/src/dispatch/for_in.rs | 1 + crates/oxide_vm/src/dispatch/member.rs | 1 + crates/oxide_vm/src/dispatch/misc.rs | 1 + crates/oxide_vm/src/dispatch/mod.rs | 9 + crates/oxide_vm/src/dispatch/property.rs | 1 + crates/oxide_vm/src/lib.rs | 2 + crates/oxide_vm/src/vm.rs | 1512 ++--------------- 26 files changed, 1186 insertions(+), 1393 deletions(-) create mode 100644 crates/oxide_vm/src/bindings/bind_array.rs create mode 100644 crates/oxide_vm/src/bindings/bind_boolean.rs create mode 100644 crates/oxide_vm/src/bindings/bind_date.rs create mode 100644 crates/oxide_vm/src/bindings/bind_error.rs create mode 100644 crates/oxide_vm/src/bindings/bind_function.rs create mode 100644 crates/oxide_vm/src/bindings/bind_json.rs create mode 100644 crates/oxide_vm/src/bindings/bind_map.rs create mode 100644 crates/oxide_vm/src/bindings/bind_math.rs create mode 100644 crates/oxide_vm/src/bindings/bind_number.rs create mode 100644 crates/oxide_vm/src/bindings/bind_object.rs create mode 100644 crates/oxide_vm/src/bindings/bind_set.rs create mode 100644 crates/oxide_vm/src/bindings/bind_string.rs create mode 100644 crates/oxide_vm/src/bindings/mod.rs create mode 100644 crates/oxide_vm/src/dispatch/arithmetic.rs create mode 100644 crates/oxide_vm/src/dispatch/call.rs create mode 100644 crates/oxide_vm/src/dispatch/comparison.rs create mode 100644 crates/oxide_vm/src/dispatch/control_flow.rs create mode 100644 crates/oxide_vm/src/dispatch/exception.rs create mode 100644 crates/oxide_vm/src/dispatch/for_in.rs create mode 100644 crates/oxide_vm/src/dispatch/member.rs create mode 100644 crates/oxide_vm/src/dispatch/misc.rs create mode 100644 crates/oxide_vm/src/dispatch/mod.rs create mode 100644 crates/oxide_vm/src/dispatch/property.rs diff --git a/crates/oxide_kernel/src/builtin.rs b/crates/oxide_kernel/src/builtin.rs index f003677a..9d609319 100644 --- a/crates/oxide_kernel/src/builtin.rs +++ b/crates/oxide_kernel/src/builtin.rs @@ -12,6 +12,14 @@ macro_rules! bind_method { }; } +#[macro_export] +macro_rules! bind_methods { + ($world:expr, $target:expr, $sf:expr, $sh:expr, + $(($name:literal, $func:path, $nargs:literal)),* $(,)?) => { + $( bind_method!($world, $target, $sf, $sh, $name, $func, $nargs); )* + }; +} + pub struct ObjectMethods { pub keys: *const (), pub create: *const (), diff --git a/crates/oxide_vm/src/bindings/bind_array.rs b/crates/oxide_vm/src/bindings/bind_array.rs new file mode 100644 index 00000000..9d1798d6 --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_array.rs @@ -0,0 +1,45 @@ +use std::sync::Arc; + +use crate::bind_constructor_hash; +use oxide_kernel::builtin::ArrayMethods; +use oxide_kernel::kernel::OxideKernel; +use oxide_types::object::JsObject; + +pub fn bind_array(kernel: &Arc, global: &mut JsObject) { + let _array_methods = ArrayMethods { + push: crate::builtins::array::array_push as *const (), + pop: crate::builtins::array::array_pop as *const (), + slice: crate::builtins::array::array_slice as *const (), + splice: crate::builtins::array::array_splice as *const (), + concat: crate::builtins::array::array_concat as *const (), + join: crate::builtins::array::array_join as *const (), + index_of: crate::builtins::array::array_index_of as *const (), + includes: crate::builtins::array::array_includes as *const (), + reverse: crate::builtins::array::array_reverse as *const (), + for_each: crate::builtins::array::array_for_each as *const (), + map: crate::builtins::array::array_map as *const (), + filter: crate::builtins::array::array_filter as *const (), + reduce: crate::builtins::array::array_reduce as *const (), + find: crate::builtins::array::array_find as *const (), + some: crate::builtins::array::array_some as *const (), + every: crate::builtins::array::array_every as *const (), + flat: crate::builtins::array::array_flat as *const (), + flat_map: crate::builtins::array::array_flat_map as *const (), + }; + + kernel.builtin_world().bind_array_methods( + &_array_methods, + kernel.string_forge().as_ref(), + kernel.shape_forge().as_ref(), + ); + + let ctor_ptr = kernel.builtin_world().array_constructor.as_ptr() as *mut JsObject; + bind_constructor_hash!( + kernel, + global, + "Array", + ctor_ptr, + crate::builtins::array::array_constructor, + 1 + ); +} diff --git a/crates/oxide_vm/src/bindings/bind_boolean.rs b/crates/oxide_vm/src/bindings/bind_boolean.rs new file mode 100644 index 00000000..e7fa3b44 --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_boolean.rs @@ -0,0 +1,48 @@ +use std::sync::Arc; + +use crate::bind_constructor_hash; +use oxide_kernel::bind_method; +use oxide_kernel::kernel::OxideKernel; +use oxide_types::object::JsObject; + +pub fn bind_boolean(kernel: &Arc, global: &mut JsObject) { + let ctor_ptr = kernel.builtin_world().boolean_constructor.as_ptr() as *mut JsObject; + let ctor = unsafe { &mut *ctor_ptr }; + let proto_ptr = kernel.builtin_world().boolean_proto.as_ptr() as *mut JsObject; + let proto = unsafe { &mut *proto_ptr }; + let sf = kernel.string_forge().as_ref(); + let sh = kernel.shape_forge().as_ref(); + + ctor.set_native_fn(Some( + crate::builtins::boolean::boolean_constructor as *const (), + )); + ctor.set_native_arg_count(1); + + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "valueOf", + crate::builtins::boolean::boolean_prototype_value_of, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "toString", + crate::builtins::boolean::boolean_prototype_to_string, + 0 + ); + + bind_constructor_hash!( + kernel, + global, + "Boolean", + ctor_ptr, + crate::builtins::boolean::boolean_constructor, + 1 + ); +} diff --git a/crates/oxide_vm/src/bindings/bind_date.rs b/crates/oxide_vm/src/bindings/bind_date.rs new file mode 100644 index 00000000..60397857 --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_date.rs @@ -0,0 +1,351 @@ +use std::sync::Arc; + +use oxide_kernel::bind_method; +use oxide_kernel::kernel::OxideKernel; +use oxide_types::object::JsObject; +use oxide_types::value::JsValue; + +pub fn bind_date(kernel: &Arc, global: &mut JsObject) { + let ctor_ptr = kernel.builtin_world().date_constructor.as_ptr() as *mut JsObject; + let ctor = unsafe { &mut *ctor_ptr }; + let proto_ptr = kernel.builtin_world().date_proto.as_ptr() as *mut JsObject; + let proto = unsafe { &mut *proto_ptr }; + let sf = kernel.string_forge().as_ref(); + let sh = kernel.shape_forge().as_ref(); + + ctor.set_native_fn(Some(crate::builtins::date::date_constructor as *const ())); + ctor.set_native_arg_count(7); + + bind_method!( + kernel.builtin_world(), + ctor, + sf, + sh, + "now", + crate::builtins::date::date_now, + 0 + ); + bind_method!( + kernel.builtin_world(), + ctor, + sf, + sh, + "parse", + crate::builtins::date::date_parse, + 1 + ); + bind_method!( + kernel.builtin_world(), + ctor, + sf, + sh, + "UTC", + crate::builtins::date::date_utc, + 7 + ); + + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getTime", + crate::builtins::date::date_get_time, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getFullYear", + crate::builtins::date::date_get_full_year, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getMonth", + crate::builtins::date::date_get_month, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getDate", + crate::builtins::date::date_get_date, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getDay", + crate::builtins::date::date_get_day, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getHours", + crate::builtins::date::date_get_hours, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getMinutes", + crate::builtins::date::date_get_minutes, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getSeconds", + crate::builtins::date::date_get_seconds, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getMilliseconds", + crate::builtins::date::date_get_milliseconds, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getUTCFullYear", + crate::builtins::date::date_get_utc_full_year, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getUTCMonth", + crate::builtins::date::date_get_utc_month, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getUTCDate", + crate::builtins::date::date_get_utc_date, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getUTCDay", + crate::builtins::date::date_get_utc_day, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getUTCHours", + crate::builtins::date::date_get_utc_hours, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getUTCMinutes", + crate::builtins::date::date_get_utc_minutes, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getUTCSeconds", + crate::builtins::date::date_get_utc_seconds, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getUTCMilliseconds", + crate::builtins::date::date_get_utc_milliseconds, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "getTimezoneOffset", + crate::builtins::date::date_get_timezone_offset, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "setTime", + crate::builtins::date::date_set_time, + 1 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "setFullYear", + crate::builtins::date::date_set_full_year, + 3 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "setMonth", + crate::builtins::date::date_set_month, + 2 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "setDate", + crate::builtins::date::date_set_date, + 1 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "setHours", + crate::builtins::date::date_set_hours, + 4 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "setMinutes", + crate::builtins::date::date_set_minutes, + 3 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "setSeconds", + crate::builtins::date::date_set_seconds, + 2 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "setMilliseconds", + crate::builtins::date::date_set_milliseconds, + 1 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "toISOString", + crate::builtins::date::date_to_iso_string, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "toJSON", + crate::builtins::date::date_to_json, + 1 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "toString", + crate::builtins::date::date_to_string, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "toDateString", + crate::builtins::date::date_to_date_string, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "toTimeString", + crate::builtins::date::date_to_time_string, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "toUTCString", + crate::builtins::date::date_to_utc_string, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "valueOf", + crate::builtins::date::date_value_of, + 0 + ); + + let si_d = kernel.string_forge().intern("Date").0; + let d_shape = kernel.shape_forge().make_shape(global.shape_id(), si_d); + let d_val = JsValue::from_js_object(ctor_ptr); + global.set_shape_id(d_shape); + global.ensure_hash_props().push(Box::new(d_val)); + global.bump_generation(); +} diff --git a/crates/oxide_vm/src/bindings/bind_error.rs b/crates/oxide_vm/src/bindings/bind_error.rs new file mode 100644 index 00000000..da4d687d --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_error.rs @@ -0,0 +1,37 @@ +use std::sync::Arc; + +use oxide_kernel::builtin::ErrorMethods; +use oxide_kernel::kernel::OxideKernel; +use oxide_types::object::JsObject; +use oxide_types::value::JsValue; + +pub fn bind_error(kernel: &Arc, global: &mut JsObject) { + let error_methods = ErrorMethods { + error: crate::builtins::error::error_constructor as *const (), + type_error: crate::builtins::error::type_error_constructor as *const (), + reference_error: crate::builtins::error::reference_error_constructor as *const (), + range_error: crate::builtins::error::range_error_constructor as *const (), + syntax_error: crate::builtins::error::syntax_error_constructor as *const (), + uri_error: crate::builtins::error::uri_error_constructor as *const (), + eval_error: crate::builtins::error::eval_error_constructor as *const (), + }; + kernel.builtin_world().bind_error_methods( + &error_methods, + kernel.string_forge().as_ref(), + kernel.shape_forge().as_ref(), + ); + + let si_err = kernel.string_forge().intern("Error").0; + let err_shape = kernel.shape_forge().make_shape(global.shape_id(), si_err); + let err_val = + JsValue::from_js_object(kernel.builtin_world().error_constructor.as_ptr() as *mut JsObject); + global.set_shape_id(err_shape); + global.ensure_hash_props().push(Box::new(err_val)); + global.bump_generation(); + + { + let err_ctor_ptr = kernel.builtin_world().error_constructor.as_ptr() as *mut JsObject; + let err_ctor = unsafe { &mut *err_ctor_ptr }; + err_ctor.set_native_fn(Some(crate::builtins::error::error_constructor as *const ())); + } +} diff --git a/crates/oxide_vm/src/bindings/bind_function.rs b/crates/oxide_vm/src/bindings/bind_function.rs new file mode 100644 index 00000000..9e4f6710 --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_function.rs @@ -0,0 +1,17 @@ +use std::sync::Arc; + +use oxide_kernel::builtin::FunctionMethods; +use oxide_kernel::kernel::OxideKernel; + +pub fn bind_function(kernel: &Arc) { + let function_methods = FunctionMethods { + call: crate::builtins::function::function_call as *const (), + apply: crate::builtins::function::function_apply as *const (), + bind: crate::builtins::function::function_bind as *const (), + }; + kernel.builtin_world().bind_function_methods( + &function_methods, + kernel.string_forge().as_ref(), + kernel.shape_forge().as_ref(), + ); +} diff --git a/crates/oxide_vm/src/bindings/bind_json.rs b/crates/oxide_vm/src/bindings/bind_json.rs new file mode 100644 index 00000000..222c24b6 --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_json.rs @@ -0,0 +1,38 @@ +use std::sync::Arc; + +use oxide_kernel::bind_method; +use oxide_kernel::kernel::OxideKernel; +use oxide_types::object::JsObject; +use oxide_types::value::JsValue; + +pub fn bind_json(kernel: &Arc, global: &mut JsObject) { + let json_ptr = kernel.builtin_world().json_object.as_ptr() as *mut JsObject; + let json = unsafe { &mut *json_ptr }; + + bind_method!( + kernel.builtin_world(), + json, + kernel.string_forge().as_ref(), + kernel.shape_forge().as_ref(), + "parse", + crate::builtins::json::json_parse, + 1 + ); + bind_method!( + kernel.builtin_world(), + json, + kernel.string_forge().as_ref(), + kernel.shape_forge().as_ref(), + "stringify", + crate::builtins::json::json_stringify, + 1 + ); + + let si_j = kernel.string_forge().intern("JSON").0; + let j_shape = kernel.shape_forge().make_shape(global.shape_id(), si_j); + let j_val = + JsValue::from_js_object(kernel.builtin_world().json_object.as_ptr() as *mut JsObject); + global.set_shape_id(j_shape); + global.ensure_hash_props().push(Box::new(j_val)); + global.bump_generation(); +} diff --git a/crates/oxide_vm/src/bindings/bind_map.rs b/crates/oxide_vm/src/bindings/bind_map.rs new file mode 100644 index 00000000..2aa8bf06 --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_map.rs @@ -0,0 +1,82 @@ +use std::sync::Arc; + +use crate::bind_constructor_hash; +use oxide_kernel::bind_method; +use oxide_kernel::kernel::OxideKernel; +use oxide_types::object::JsObject; + +pub fn bind_map(kernel: &Arc, global: &mut JsObject) { + let ctor_ptr = kernel.builtin_world().map_constructor.as_ptr() as *mut JsObject; + let ctor = unsafe { &mut *ctor_ptr }; + let proto_ptr = kernel.builtin_world().map_proto.as_ptr() as *mut JsObject; + + ctor.set_native_fn(Some(crate::builtins::map::map_constructor as *const ())); + ctor.set_native_arg_count(1); + let proto = unsafe { &mut *proto_ptr }; + let sf = kernel.string_forge().as_ref(); + let sh = kernel.shape_forge().as_ref(); + + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "set", + crate::builtins::map::map_set, + 2 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "get", + crate::builtins::map::map_get, + 1 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "has", + crate::builtins::map::map_has, + 1 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "delete", + crate::builtins::map::map_delete, + 1 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "clear", + crate::builtins::map::map_clear, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "size", + crate::builtins::map::map_size, + 0 + ); + + bind_constructor_hash!( + kernel, + global, + "Map", + ctor_ptr, + crate::builtins::map::map_constructor, + 1 + ); +} diff --git a/crates/oxide_vm/src/bindings/bind_math.rs b/crates/oxide_vm/src/bindings/bind_math.rs new file mode 100644 index 00000000..f624d21d --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_math.rs @@ -0,0 +1,84 @@ +use std::sync::Arc; + +use oxide_kernel::kernel::OxideKernel; +use oxide_kernel::{bind_method, bind_methods}; +use oxide_types::object::JsObject; +use oxide_types::value::JsValue; + +pub fn bind_math(kernel: &Arc, global: &mut JsObject) { + let math_ptr = kernel.builtin_world().math_object.as_ptr() as *mut JsObject; + let math = unsafe { &mut *math_ptr }; + + let bw = kernel.builtin_world(); + let sf = kernel.string_forge().as_ref(); + let sh = kernel.shape_forge().as_ref(); + + bind_methods!( + bw, + math, + sf, + sh, + ("abs", crate::builtins::math::math_abs, 1), + ("acos", crate::builtins::math::math_acos, 1), + ("asin", crate::builtins::math::math_asin, 1), + ("atan", crate::builtins::math::math_atan, 1), + ("atan2", crate::builtins::math::math_atan2, 2), + ("cbrt", crate::builtins::math::math_cbrt, 1), + ("ceil", crate::builtins::math::math_ceil, 1), + ("cos", crate::builtins::math::math_cos, 1), + ("cosh", crate::builtins::math::math_cosh, 1), + ("exp", crate::builtins::math::math_exp, 1), + ("floor", crate::builtins::math::math_floor, 1), + ("hypot", crate::builtins::math::math_hypot, 2), + ("imul", crate::builtins::math::math_imul, 2), + ("log", crate::builtins::math::math_log, 1), + ("log10", crate::builtins::math::math_log10, 1), + ("log2", crate::builtins::math::math_log2, 1), + ("max", crate::builtins::math::math_max, 2), + ("min", crate::builtins::math::math_min, 2), + ("pow", crate::builtins::math::math_pow, 2), + ("random", crate::builtins::math::math_random, 0), + ("round", crate::builtins::math::math_round, 1), + ("sign", crate::builtins::math::math_sign, 1), + ("sin", crate::builtins::math::math_sin, 1), + ("sinh", crate::builtins::math::math_sinh, 1), + ("sqrt", crate::builtins::math::math_sqrt, 1), + ("tan", crate::builtins::math::math_tan, 1), + ("tanh", crate::builtins::math::math_tanh, 1), + ("trunc", crate::builtins::math::math_trunc, 1), + ("acosh", crate::builtins::math::math_acosh, 1), + ("asinh", crate::builtins::math::math_asinh, 1), + ("atanh", crate::builtins::math::math_atanh, 1), + ("clz32", crate::builtins::math::math_clz32, 1), + ("expm1", crate::builtins::math::math_expm1, 1), + ("fround", crate::builtins::math::math_fround, 1), + ("log1p", crate::builtins::math::math_log1p, 1), + ); + + for (name, val) in [ + ("PI", std::f64::consts::PI), + ("E", std::f64::consts::E), + ("LN10", std::f64::consts::LN_10), + ("LN2", std::f64::consts::LN_2), + ("LOG10E", std::f64::consts::LOG10_E), + ("LOG2E", std::f64::consts::LOG2_E), + ("SQRT1_2", std::f64::consts::FRAC_1_SQRT_2), + ("SQRT2", std::f64::consts::SQRT_2), + ] { + let si = kernel.string_forge().as_ref().intern(name).0; + let sh_c = kernel + .shape_forge() + .as_ref() + .make_shape(math.shape_id(), si); + math.set_shape_id(sh_c); + math.ensure_hash_props().push(Box::new(JsValue::float(val))); + } + + let si_m = kernel.string_forge().intern("Math").0; + let m_shape = kernel.shape_forge().make_shape(global.shape_id(), si_m); + let m_val = + JsValue::from_js_object(kernel.builtin_world().math_object.as_ptr() as *mut JsObject); + global.set_shape_id(m_shape); + global.ensure_hash_props().push(Box::new(m_val)); + global.bump_generation(); +} diff --git a/crates/oxide_vm/src/bindings/bind_number.rs b/crates/oxide_vm/src/bindings/bind_number.rs new file mode 100644 index 00000000..78f5f258 --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_number.rs @@ -0,0 +1,62 @@ +use std::sync::Arc; + +use oxide_kernel::bind_method; +use oxide_kernel::builtin::NumberMethods; +use oxide_kernel::kernel::OxideKernel; +use oxide_types::object::JsObject; +use oxide_types::value::JsValue; + +pub fn bind_number(kernel: &Arc, global: &mut JsObject) { + let number_methods = NumberMethods { + is_nan: crate::builtins::number::number_is_nan as *const (), + is_finite: crate::builtins::number::number_is_finite as *const (), + parse_int: crate::builtins::number::number_parse_int as *const (), + parse_float: crate::builtins::number::number_parse_float as *const (), + to_string: crate::builtins::number::number_to_string as *const (), + to_fixed: crate::builtins::number::number_to_fixed as *const (), + }; + kernel.builtin_world().bind_number_methods( + &number_methods, + kernel.string_forge().as_ref(), + kernel.shape_forge().as_ref(), + ); + + let si_num = kernel.string_forge().intern("Number").0; + let num_shape = kernel.shape_forge().make_shape(global.shape_id(), si_num); + let num_val = JsValue::from_js_object( + kernel.builtin_world().number_constructor.as_ptr() as *mut JsObject + ); + global.set_shape_id(num_shape); + global.ensure_hash_props().push(Box::new(num_val)); + global.bump_generation(); + + { + let num_ctor_ptr = kernel.builtin_world().number_constructor.as_ptr() as *mut JsObject; + let num_ctor = unsafe { &mut *num_ctor_ptr }; + num_ctor.set_native_fn(Some( + crate::builtins::number::number_constructor as *const (), + )); + num_ctor.set_native_arg_count(1); + } + + let pi_fn = crate::builtins::number::number_parse_int as *const (); + let pf_fn = crate::builtins::number::number_parse_float as *const (); + bind_method!( + kernel.builtin_world(), + global, + kernel.string_forge().as_ref(), + kernel.shape_forge().as_ref(), + "parseInt", + pi_fn, + 1 + ); + bind_method!( + kernel.builtin_world(), + global, + kernel.string_forge().as_ref(), + kernel.shape_forge().as_ref(), + "parseFloat", + pf_fn, + 1 + ); +} diff --git a/crates/oxide_vm/src/bindings/bind_object.rs b/crates/oxide_vm/src/bindings/bind_object.rs new file mode 100644 index 00000000..4c294539 --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_object.rs @@ -0,0 +1,39 @@ +use std::sync::Arc; + +use crate::bind_constructor; +use oxide_kernel::builtin::ObjectMethods; +use oxide_kernel::kernel::OxideKernel; +use oxide_types::object::JsObject; + +pub fn bind_object(kernel: &Arc, global: &mut JsObject) { + let methods = ObjectMethods { + keys: crate::builtins::object::object_keys as *const (), + create: crate::builtins::object::object_create as *const (), + assign: crate::builtins::object::object_assign as *const (), + define_property: crate::builtins::object::object_define_property as *const (), + get_own_property_descriptor: crate::builtins::object::object_get_own_property_descriptor + as *const (), + freeze: crate::builtins::object::object_freeze as *const (), + seal: crate::builtins::object::object_seal as *const (), + prevent_extensions: crate::builtins::object::object_prevent_extensions as *const (), + is_frozen: crate::builtins::object::object_is_frozen as *const (), + is_sealed: crate::builtins::object::object_is_sealed as *const (), + is_extensible: crate::builtins::object::object_is_extensible as *const (), + get_own_property_names: crate::builtins::object::object_get_own_property_names as *const (), + }; + kernel.builtin_world().bind_object_methods( + &methods, + kernel.string_forge().as_ref(), + kernel.shape_forge().as_ref(), + ); + + let ctor_ptr = kernel.builtin_world().object_constructor.as_ptr() as *mut JsObject; + bind_constructor!( + kernel, + global, + "Object", + ctor_ptr, + crate::builtins::object::object_constructor, + 1 + ); +} diff --git a/crates/oxide_vm/src/bindings/bind_set.rs b/crates/oxide_vm/src/bindings/bind_set.rs new file mode 100644 index 00000000..657c8425 --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_set.rs @@ -0,0 +1,73 @@ +use std::sync::Arc; + +use crate::bind_constructor_hash; +use oxide_kernel::bind_method; +use oxide_kernel::kernel::OxideKernel; +use oxide_types::object::JsObject; + +pub fn bind_set(kernel: &Arc, global: &mut JsObject) { + let ctor_ptr = kernel.builtin_world().set_constructor.as_ptr() as *mut JsObject; + let ctor = unsafe { &mut *ctor_ptr }; + let proto_ptr = kernel.builtin_world().set_proto.as_ptr() as *mut JsObject; + + ctor.set_native_fn(Some(crate::builtins::set::set_constructor as *const ())); + ctor.set_native_arg_count(1); + let proto = unsafe { &mut *proto_ptr }; + let sf = kernel.string_forge().as_ref(); + let sh = kernel.shape_forge().as_ref(); + + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "add", + crate::builtins::set::set_add, + 1 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "has", + crate::builtins::set::set_has, + 1 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "delete", + crate::builtins::set::set_delete, + 1 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "clear", + crate::builtins::set::set_clear, + 0 + ); + bind_method!( + kernel.builtin_world(), + proto, + sf, + sh, + "size", + crate::builtins::set::set_size, + 0 + ); + + bind_constructor_hash!( + kernel, + global, + "Set", + ctor_ptr, + crate::builtins::set::set_constructor, + 1 + ); +} diff --git a/crates/oxide_vm/src/bindings/bind_string.rs b/crates/oxide_vm/src/bindings/bind_string.rs new file mode 100644 index 00000000..69a95fc7 --- /dev/null +++ b/crates/oxide_vm/src/bindings/bind_string.rs @@ -0,0 +1,44 @@ +use std::sync::Arc; + +use oxide_kernel::builtin::StringMethods; +use oxide_kernel::kernel::OxideKernel; +use oxide_types::object::JsObject; +use oxide_types::value::JsValue; + +pub fn bind_string(kernel: &Arc, global: &mut JsObject) { + let string_methods = StringMethods { + index_of: crate::builtins::string::string_index_of as *const (), + includes: crate::builtins::string::string_includes as *const (), + char_at: crate::builtins::string::string_char_at as *const (), + char_code_at: crate::builtins::string::string_char_code_at as *const (), + concat: crate::builtins::string::string_concat as *const (), + slice: crate::builtins::string::string_slice as *const (), + substring: crate::builtins::string::string_substring as *const (), + to_upper_case: crate::builtins::string::string_to_upper_case as *const (), + to_lower_case: crate::builtins::string::string_to_lower_case as *const (), + trim: crate::builtins::string::string_trim as *const (), + repeat: crate::builtins::string::string_repeat as *const (), + pad_start: crate::builtins::string::string_pad_start as *const (), + pad_end: crate::builtins::string::string_pad_end as *const (), + starts_with: crate::builtins::string::string_starts_with as *const (), + ends_with: crate::builtins::string::string_ends_with as *const (), + split: crate::builtins::string::string_split as *const (), + replace: crate::builtins::string::string_replace as *const (), + match_fn: crate::builtins::string::string_match_fn as *const (), + search: crate::builtins::string::string_search as *const (), + }; + kernel.builtin_world().bind_string_methods( + &string_methods, + kernel.string_forge().as_ref(), + kernel.shape_forge().as_ref(), + ); + + let si_str = kernel.string_forge().intern("String").0; + let str_shape = kernel.shape_forge().make_shape(global.shape_id(), si_str); + let str_val = JsValue::from_js_object( + kernel.builtin_world().string_constructor.as_ptr() as *mut JsObject + ); + global.set_shape_id(str_shape); + global.ensure_hash_props().push(Box::new(str_val)); + global.bump_generation(); +} diff --git a/crates/oxide_vm/src/bindings/mod.rs b/crates/oxide_vm/src/bindings/mod.rs new file mode 100644 index 00000000..23d7e7de --- /dev/null +++ b/crates/oxide_vm/src/bindings/mod.rs @@ -0,0 +1,63 @@ +pub mod bind_array; +pub mod bind_boolean; +pub mod bind_date; +pub mod bind_error; +pub mod bind_function; +pub mod bind_json; +pub mod bind_map; +pub mod bind_math; +pub mod bind_number; +pub mod bind_object; +pub mod bind_set; +pub mod bind_string; + +use std::sync::Arc; + +use oxide_kernel::kernel::OxideKernel; + +#[macro_export] +macro_rules! bind_constructor { + ($kernel:expr, $global:expr, $name:literal, $ctor_ptr:expr, $ctor_fn:path, $nargs:literal) => {{ + let si = $kernel.string_forge().intern($name).0; + let shape = $kernel.shape_forge().make_shape($global.shape_id(), si); + let val = $crate::JsValue::from_js_object($ctor_ptr); + $global.set_shape_id(shape); + $global.push_prop(val); + let ctor = unsafe { &mut *$ctor_ptr }; + ctor.set_native_fn(Some($ctor_fn as *const ())); + ctor.set_native_arg_count($nargs); + }}; +} + +#[macro_export] +macro_rules! bind_constructor_hash { + ($kernel:expr, $global:expr, $name:literal, $ctor_ptr:expr, $ctor_fn:path, $nargs:literal) => {{ + let si = $kernel.string_forge().intern($name).0; + let shape = $kernel.shape_forge().make_shape($global.shape_id(), si); + let val = $crate::JsValue::from_js_object($ctor_ptr); + $global.set_shape_id(shape); + $global.ensure_hash_props().push(Box::new(val)); + $global.bump_generation(); + let ctor = unsafe { &mut *$ctor_ptr }; + ctor.set_native_fn(Some($ctor_fn as *const ())); + ctor.set_native_arg_count($nargs); + }}; +} + +pub fn init_kernel_builtins(kernel: &Arc) { + let global_ptr = kernel.global_object().as_ptr() as *mut oxide_types::object::JsObject; + let global = unsafe { &mut *global_ptr }; + + bind_object::bind_object(kernel, global); + bind_array::bind_array(kernel, global); + bind_error::bind_error(kernel, global); + bind_string::bind_string(kernel, global); + bind_number::bind_number(kernel, global); + bind_math::bind_math(kernel, global); + bind_json::bind_json(kernel, global); + bind_date::bind_date(kernel, global); + bind_set::bind_set(kernel, global); + bind_map::bind_map(kernel, global); + bind_boolean::bind_boolean(kernel, global); + bind_function::bind_function(kernel); +} diff --git a/crates/oxide_vm/src/dispatch/arithmetic.rs b/crates/oxide_vm/src/dispatch/arithmetic.rs new file mode 100644 index 00000000..0e9d58a1 --- /dev/null +++ b/crates/oxide_vm/src/dispatch/arithmetic.rs @@ -0,0 +1 @@ +// dispatch helper functions extracted from vm.rs diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs new file mode 100644 index 00000000..7f6f9303 --- /dev/null +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -0,0 +1,57 @@ +use crate::native::NativeFn; +use crate::vm::Vm; +use oxide_types::object::JsObject; +use oxide_types::value::JsValue; + +impl Vm { + #[inline(always)] + pub(crate) fn build_native_args( + first_arg_reg: u8, + arg_count: usize, + this_reg: u8, + ) -> ([u8; 257], usize) { + let mut args_buf = [0u8; 257]; + args_buf[0] = this_reg; + let n = arg_count.min(256); + for i in 0..n { + args_buf[i + 1] = first_arg_reg.wrapping_add(i as u8); + } + (args_buf, n + 1) + } + + #[inline(always)] + pub(crate) fn dispatch_native_call( + &mut self, + obj: &JsObject, + callee: JsValue, + this_reg: u8, + first_arg_reg: u8, + arg_count: usize, + ) -> Result<(), String> { + let (args_buf, len) = Self::build_native_args(first_arg_reg, arg_count, this_reg); + let args_slice = &args_buf[..len]; + + let func: NativeFn = unsafe { std::mem::transmute(obj.native_fn().unwrap()) }; + self.regs[254] = callee; + match func(self, args_slice) { + Ok(val) => { + self.regs[0] = val; + Ok(()) + } + Err(err_val) => { + let msg = if err_val.is_string() { + self.kernel() + .string_forge() + .lookup(err_val.as_string_index()) + .unwrap_or_else(|| format!("{err_val}")) + } else { + format!("{err_val}") + }; + let error = crate::builtins::error::create_error(self, &msg); + self.exception_value = Some(error); + self.pending_error_kind = Some("Error"); + self.unwind() + } + } + } +} diff --git a/crates/oxide_vm/src/dispatch/comparison.rs b/crates/oxide_vm/src/dispatch/comparison.rs new file mode 100644 index 00000000..0e9d58a1 --- /dev/null +++ b/crates/oxide_vm/src/dispatch/comparison.rs @@ -0,0 +1 @@ +// dispatch helper functions extracted from vm.rs diff --git a/crates/oxide_vm/src/dispatch/control_flow.rs b/crates/oxide_vm/src/dispatch/control_flow.rs new file mode 100644 index 00000000..0e9d58a1 --- /dev/null +++ b/crates/oxide_vm/src/dispatch/control_flow.rs @@ -0,0 +1 @@ +// dispatch helper functions extracted from vm.rs diff --git a/crates/oxide_vm/src/dispatch/exception.rs b/crates/oxide_vm/src/dispatch/exception.rs new file mode 100644 index 00000000..0e9d58a1 --- /dev/null +++ b/crates/oxide_vm/src/dispatch/exception.rs @@ -0,0 +1 @@ +// dispatch helper functions extracted from vm.rs diff --git a/crates/oxide_vm/src/dispatch/for_in.rs b/crates/oxide_vm/src/dispatch/for_in.rs new file mode 100644 index 00000000..0e9d58a1 --- /dev/null +++ b/crates/oxide_vm/src/dispatch/for_in.rs @@ -0,0 +1 @@ +// dispatch helper functions extracted from vm.rs diff --git a/crates/oxide_vm/src/dispatch/member.rs b/crates/oxide_vm/src/dispatch/member.rs new file mode 100644 index 00000000..0e9d58a1 --- /dev/null +++ b/crates/oxide_vm/src/dispatch/member.rs @@ -0,0 +1 @@ +// dispatch helper functions extracted from vm.rs diff --git a/crates/oxide_vm/src/dispatch/misc.rs b/crates/oxide_vm/src/dispatch/misc.rs new file mode 100644 index 00000000..0e9d58a1 --- /dev/null +++ b/crates/oxide_vm/src/dispatch/misc.rs @@ -0,0 +1 @@ +// dispatch helper functions extracted from vm.rs diff --git a/crates/oxide_vm/src/dispatch/mod.rs b/crates/oxide_vm/src/dispatch/mod.rs new file mode 100644 index 00000000..50991eb1 --- /dev/null +++ b/crates/oxide_vm/src/dispatch/mod.rs @@ -0,0 +1,9 @@ +pub(crate) mod arithmetic; +pub(crate) mod call; +pub(crate) mod comparison; +pub(crate) mod control_flow; +pub(crate) mod exception; +pub(crate) mod for_in; +pub(crate) mod member; +pub(crate) mod misc; +pub(crate) mod property; diff --git a/crates/oxide_vm/src/dispatch/property.rs b/crates/oxide_vm/src/dispatch/property.rs new file mode 100644 index 00000000..0e9d58a1 --- /dev/null +++ b/crates/oxide_vm/src/dispatch/property.rs @@ -0,0 +1 @@ +// dispatch helper functions extracted from vm.rs diff --git a/crates/oxide_vm/src/lib.rs b/crates/oxide_vm/src/lib.rs index 13c44a14..6fd5578c 100644 --- a/crates/oxide_vm/src/lib.rs +++ b/crates/oxide_vm/src/lib.rs @@ -1,7 +1,9 @@ #![doc = "OxideJS - Register-based VM with epoch arena memory"] +pub mod bindings; pub mod builtins; pub mod coercion; +mod dispatch; pub mod native; pub mod vm; pub mod vm_pool; diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index 7ab48ce3..af3fb52f 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -6,12 +6,10 @@ use oxide_compiler::compiler::Constant; use oxide_compiler::module::CompiledModule; use oxide_compiler::opcode::{self, OpCode}; +use crate::bindings; +pub use crate::bindings::init_kernel_builtins; use crate::coercion; use crate::native::NativeFn; -use oxide_kernel::bind_method; -use oxide_kernel::builtin::{ - ArrayMethods, ErrorMethods, FunctionMethods, NumberMethods, ObjectMethods, StringMethods, -}; use oxide_kernel::kernel::{KernelConfig, OxideKernel}; use oxide_kernel::prop_forge::PropTemplate; use oxide_kernel::shape_forge::EMPTY_SHAPE_ID; @@ -19,23 +17,6 @@ use oxide_types::mem::{Epoch, P}; use oxide_types::object::JsObject; use oxide_types::value::JsValue; -/// Invoke a native function via CALL_NATIVE dispatch. -/// args[0] = this_reg, args[1..=n] = contiguous arg registers. -#[allow(unused_macros)] -macro_rules! native_call { - ($vm:ident, $callee:expr, $this_reg:expr, $first_arg_reg:expr, $arg_count:expr) => {{ - let mut args_buf = [0u8; 257]; - args_buf[0] = $this_reg; - for i in 0..($arg_count as usize).min(256) { - args_buf[i + 1] = $first_arg_reg.wrapping_add(i as u8); - } - let args_slice = &args_buf[..($arg_count as usize).min(256) + 1]; - let func: NativeFn = unsafe { std::mem::transmute($callee.native_fn().unwrap()) }; - $vm.regs[254] = JsValue::from_js_object($callee as *const JsObject as *mut JsObject); - func($vm, args_slice) - }}; -} - #[allow(unused_macros)] macro_rules! throw_err { ($self:ident, Error, $msg:expr) => {{ @@ -76,6 +57,82 @@ macro_rules! throw_err { }}; } +macro_rules! binary_arith { + ($self:ident, $a:expr, $b:expr, $rd:expr, $op:tt) => {{ + let l = coercion::to_number($self.regs[$a], $self.kernel.string_forge().as_ref()); + let r = coercion::to_number($self.regs[$b], $self.kernel.string_forge().as_ref()); + $self.regs[$rd] = JsValue::float(l $op r); + }} +} + +macro_rules! compound_arith { + ($self:ident, $rd:expr, $a:expr, $op:tt) => {{ + let l = coercion::to_number($self.regs[$rd], $self.kernel.string_forge().as_ref()); + let r = coercion::to_number($self.regs[$a], $self.kernel.string_forge().as_ref()); + $self.regs[$rd] = JsValue::float(l $op r); + }} +} + +macro_rules! set_or_create_prop { + ($self:ident, $obj:expr, $prop_name_si:expr, $new_val:expr) => {{ + if let Some(pos) = $self + .kernel + .shape_forge() + .lookup_position($obj.shape_id(), $prop_name_si) + { + $obj.set_prop_at(pos, $new_val); + } else { + let new_shape_id = $self + .kernel + .shape_forge() + .make_shape($obj.shape_id(), $prop_name_si); + $obj.set_shape_id(new_shape_id); + $obj.push_prop($new_val); + $obj.bump_generation(); + } + }}; +} + +macro_rules! member_read_prop { + ($self:ident, $obj:expr, $prop_name_si:expr) => {{ + let ext0 = $self.bytecode[$self.pc]; + let ext1 = $self.bytecode[$self.pc + 1]; + let ext2 = $self.bytecode[$self.pc + 2]; + $self.pc += 3; + let cached_shape_id = ext0 & 0x00FF_FFFF; + let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64); + + if cached_shape_id != 0 && cached_shape_id == $obj.shape_id() && cached_ptr != 0 { + unsafe { *(cached_ptr as *const JsValue) } + } else if let Some(template) = $self.kernel.prop_forge().get_template($obj.shape_id()) { + if let Some(ptr) = $self.template_prop_ptr($obj, &template) { + $self.bytecode[$self.pc - 3] = $obj.shape_id() & 0x00FF_FFFF; + $self.bytecode[$self.pc - 2] = ptr as u32; + $self.bytecode[$self.pc - 1] = (ptr as u64 >> 32) as u32; + unsafe { *ptr } + } else { + $self + .resolve_property($obj, $prop_name_si) + .unwrap_or(JsValue::undefined()) + } + } else if let Some(val) = $self.resolve_property($obj, $prop_name_si) { + let pos = $self + .kernel + .shape_forge() + .lookup_position($obj.shape_id(), $prop_name_si) + .unwrap_or(0); + if let Some(ptr) = $obj.prop_ptr_at(pos) { + $self.bytecode[$self.pc - 3] = $obj.shape_id() & 0x00FF_FFFF; + $self.bytecode[$self.pc - 2] = ptr as u32; + $self.bytecode[$self.pc - 1] = (ptr as u64 >> 32) as u32; + } + val + } else { + JsValue::undefined() + } + }}; +} + pub struct CallFrame { pub return_addr: usize, pub n_locals: u8, @@ -96,1178 +153,31 @@ pub struct TryHandler { } pub struct Vm { - regs: [JsValue; 256], - pc: usize, - bytecode: Vec, - constants: Vec, - frames: Vec, + pub(crate) regs: [JsValue; 256], + pub(crate) pc: usize, + pub(crate) bytecode: Vec, + pub(crate) constants: Vec, + pub(crate) frames: Vec, pub for_in_iters: Vec<*mut u8>, - kernel: Arc, - interned_strings: Vec, + pub(crate) kernel: Arc, + pub(crate) interned_strings: Vec, pub epoch: Epoch, pub object_prototype: P, pub math_rng_state: u64, - sub_modules: Vec, - sub_module_constants: Vec>, - /// Stack of saved bytecode for nested bytecode calls - saved_bytecode_stack: Vec>, - /// Stack of saved constants for nested bytecode calls - saved_constants_stack: Vec>, - try_stack: Vec, - exception_value: Option, - pending_exception: Option, - pending_error_kind: Option<&'static str>, -} - -fn bind_object(kernel: &Arc, global: &mut JsObject) { - let methods = ObjectMethods { - keys: crate::builtins::object::object_keys as *const (), - create: crate::builtins::object::object_create as *const (), - assign: crate::builtins::object::object_assign as *const (), - define_property: crate::builtins::object::object_define_property as *const (), - get_own_property_descriptor: crate::builtins::object::object_get_own_property_descriptor - as *const (), - freeze: crate::builtins::object::object_freeze as *const (), - seal: crate::builtins::object::object_seal as *const (), - prevent_extensions: crate::builtins::object::object_prevent_extensions as *const (), - is_frozen: crate::builtins::object::object_is_frozen as *const (), - is_sealed: crate::builtins::object::object_is_sealed as *const (), - is_extensible: crate::builtins::object::object_is_extensible as *const (), - get_own_property_names: crate::builtins::object::object_get_own_property_names as *const (), - }; - kernel.builtin_world().bind_object_methods( - &methods, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - ); - - let si_obj = kernel.string_forge().intern("Object").0; - let obj_shape = kernel.shape_forge().make_shape(global.shape_id(), si_obj); - let obj_val = JsValue::from_js_object( - kernel.builtin_world().object_constructor.as_ptr() as *mut JsObject - ); - global.set_shape_id(obj_shape); - global.push_prop(obj_val); - - // Set native constructor on Object - { - let obj_ctor_ptr = kernel.builtin_world().object_constructor.as_ptr() as *mut JsObject; - let obj_ctor = unsafe { &mut *obj_ctor_ptr }; - obj_ctor.set_native_fn(Some( - crate::builtins::object::object_constructor as *const (), - )); - obj_ctor.set_native_arg_count(1); - } -} - -fn bind_array(kernel: &Arc, global: &mut JsObject) { - let _array_methods = ArrayMethods { - push: crate::builtins::array::array_push as *const (), - pop: crate::builtins::array::array_pop as *const (), - slice: crate::builtins::array::array_slice as *const (), - splice: crate::builtins::array::array_splice as *const (), - concat: crate::builtins::array::array_concat as *const (), - join: crate::builtins::array::array_join as *const (), - index_of: crate::builtins::array::array_index_of as *const (), - includes: crate::builtins::array::array_includes as *const (), - reverse: crate::builtins::array::array_reverse as *const (), - for_each: crate::builtins::array::array_for_each as *const (), - map: crate::builtins::array::array_map as *const (), - filter: crate::builtins::array::array_filter as *const (), - reduce: crate::builtins::array::array_reduce as *const (), - find: crate::builtins::array::array_find as *const (), - some: crate::builtins::array::array_some as *const (), - every: crate::builtins::array::array_every as *const (), - flat: crate::builtins::array::array_flat as *const (), - flat_map: crate::builtins::array::array_flat_map as *const (), - }; - - kernel.builtin_world().bind_array_methods( - &_array_methods, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - ); - - let si_arr = kernel.string_forge().intern("Array").0; - let arr_shape = kernel.shape_forge().make_shape(global.shape_id(), si_arr); - let arr_val = - JsValue::from_js_object(kernel.builtin_world().array_constructor.as_ptr() as *mut JsObject); - global.set_shape_id(arr_shape); - global.ensure_hash_props().push(Box::new(arr_val)); - global.bump_generation(); - - // Set native constructor on Array - { - let arr_ctor_ptr = kernel.builtin_world().array_constructor.as_ptr() as *mut JsObject; - let arr_ctor = unsafe { &mut *arr_ctor_ptr }; - arr_ctor.set_native_fn(Some(crate::builtins::array::array_constructor as *const ())); - arr_ctor.set_native_arg_count(1); - } -} - -fn bind_error(kernel: &Arc, global: &mut JsObject) { - let error_methods = ErrorMethods { - error: crate::builtins::error::error_constructor as *const (), - type_error: crate::builtins::error::type_error_constructor as *const (), - reference_error: crate::builtins::error::reference_error_constructor as *const (), - range_error: crate::builtins::error::range_error_constructor as *const (), - syntax_error: crate::builtins::error::syntax_error_constructor as *const (), - uri_error: crate::builtins::error::uri_error_constructor as *const (), - eval_error: crate::builtins::error::eval_error_constructor as *const (), - }; - kernel.builtin_world().bind_error_methods( - &error_methods, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - ); - - let si_err = kernel.string_forge().intern("Error").0; - let err_shape = kernel.shape_forge().make_shape(global.shape_id(), si_err); - let err_val = - JsValue::from_js_object(kernel.builtin_world().error_constructor.as_ptr() as *mut JsObject); - global.set_shape_id(err_shape); - global.ensure_hash_props().push(Box::new(err_val)); - global.bump_generation(); - - { - let err_ctor_ptr = kernel.builtin_world().error_constructor.as_ptr() as *mut JsObject; - let err_ctor = unsafe { &mut *err_ctor_ptr }; - err_ctor.set_native_fn(Some(crate::builtins::error::error_constructor as *const ())); - } -} - -fn bind_string(kernel: &Arc, global: &mut JsObject) { - let string_methods = StringMethods { - index_of: crate::builtins::string::string_index_of as *const (), - includes: crate::builtins::string::string_includes as *const (), - char_at: crate::builtins::string::string_char_at as *const (), - char_code_at: crate::builtins::string::string_char_code_at as *const (), - concat: crate::builtins::string::string_concat as *const (), - slice: crate::builtins::string::string_slice as *const (), - substring: crate::builtins::string::string_substring as *const (), - to_upper_case: crate::builtins::string::string_to_upper_case as *const (), - to_lower_case: crate::builtins::string::string_to_lower_case as *const (), - trim: crate::builtins::string::string_trim as *const (), - repeat: crate::builtins::string::string_repeat as *const (), - pad_start: crate::builtins::string::string_pad_start as *const (), - pad_end: crate::builtins::string::string_pad_end as *const (), - starts_with: crate::builtins::string::string_starts_with as *const (), - ends_with: crate::builtins::string::string_ends_with as *const (), - split: crate::builtins::string::string_split as *const (), - replace: crate::builtins::string::string_replace as *const (), - match_fn: crate::builtins::string::string_match_fn as *const (), - search: crate::builtins::string::string_search as *const (), - }; - kernel.builtin_world().bind_string_methods( - &string_methods, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - ); - - let si_str = kernel.string_forge().intern("String").0; - let str_shape = kernel.shape_forge().make_shape(global.shape_id(), si_str); - let str_val = JsValue::from_js_object( - kernel.builtin_world().string_constructor.as_ptr() as *mut JsObject - ); - global.set_shape_id(str_shape); - global.ensure_hash_props().push(Box::new(str_val)); - global.bump_generation(); -} - -fn bind_number(kernel: &Arc, global: &mut JsObject) { - let number_methods = NumberMethods { - is_nan: crate::builtins::number::number_is_nan as *const (), - is_finite: crate::builtins::number::number_is_finite as *const (), - parse_int: crate::builtins::number::number_parse_int as *const (), - parse_float: crate::builtins::number::number_parse_float as *const (), - to_string: crate::builtins::number::number_to_string as *const (), - to_fixed: crate::builtins::number::number_to_fixed as *const (), - }; - kernel.builtin_world().bind_number_methods( - &number_methods, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - ); - - let si_num = kernel.string_forge().intern("Number").0; - let num_shape = kernel.shape_forge().make_shape(global.shape_id(), si_num); - let num_val = JsValue::from_js_object( - kernel.builtin_world().number_constructor.as_ptr() as *mut JsObject - ); - global.set_shape_id(num_shape); - global.ensure_hash_props().push(Box::new(num_val)); - global.bump_generation(); - - { - let num_ctor_ptr = kernel.builtin_world().number_constructor.as_ptr() as *mut JsObject; - let num_ctor = unsafe { &mut *num_ctor_ptr }; - num_ctor.set_native_fn(Some( - crate::builtins::number::number_constructor as *const (), - )); - num_ctor.set_native_arg_count(1); - } - - let pi_fn = crate::builtins::number::number_parse_int as *const (); - let pf_fn = crate::builtins::number::number_parse_float as *const (); - bind_method!( - kernel.builtin_world(), - global, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "parseInt", - pi_fn, - 1 - ); - bind_method!( - kernel.builtin_world(), - global, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "parseFloat", - pf_fn, - 1 - ); -} - -fn bind_math(kernel: &Arc, global: &mut JsObject) { - let math_ptr = kernel.builtin_world().math_object.as_ptr() as *mut JsObject; - let math = unsafe { &mut *math_ptr }; - - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "abs", - crate::builtins::math::math_abs, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "acos", - crate::builtins::math::math_acos, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "asin", - crate::builtins::math::math_asin, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "atan", - crate::builtins::math::math_atan, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "atan2", - crate::builtins::math::math_atan2, - 2 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "cbrt", - crate::builtins::math::math_cbrt, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "ceil", - crate::builtins::math::math_ceil, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "cos", - crate::builtins::math::math_cos, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "cosh", - crate::builtins::math::math_cosh, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "exp", - crate::builtins::math::math_exp, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "floor", - crate::builtins::math::math_floor, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "hypot", - crate::builtins::math::math_hypot, - 2 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "imul", - crate::builtins::math::math_imul, - 2 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "log", - crate::builtins::math::math_log, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "log10", - crate::builtins::math::math_log10, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "log2", - crate::builtins::math::math_log2, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "max", - crate::builtins::math::math_max, - 2 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "min", - crate::builtins::math::math_min, - 2 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "pow", - crate::builtins::math::math_pow, - 2 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "random", - crate::builtins::math::math_random, - 0 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "round", - crate::builtins::math::math_round, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "sign", - crate::builtins::math::math_sign, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "sin", - crate::builtins::math::math_sin, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "sinh", - crate::builtins::math::math_sinh, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "sqrt", - crate::builtins::math::math_sqrt, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "tan", - crate::builtins::math::math_tan, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "tanh", - crate::builtins::math::math_tanh, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "trunc", - crate::builtins::math::math_trunc, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "acosh", - crate::builtins::math::math_acosh, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "asinh", - crate::builtins::math::math_asinh, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "atanh", - crate::builtins::math::math_atanh, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "clz32", - crate::builtins::math::math_clz32, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "expm1", - crate::builtins::math::math_expm1, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "fround", - crate::builtins::math::math_fround, - 1 - ); - bind_method!( - kernel.builtin_world(), - math, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "log1p", - crate::builtins::math::math_log1p, - 1 - ); - - for (name, val) in [ - ("PI", std::f64::consts::PI), - ("E", std::f64::consts::E), - ("LN10", std::f64::consts::LN_10), - ("LN2", std::f64::consts::LN_2), - ("LOG10E", std::f64::consts::LOG10_E), - ("LOG2E", std::f64::consts::LOG2_E), - ("SQRT1_2", std::f64::consts::FRAC_1_SQRT_2), - ("SQRT2", std::f64::consts::SQRT_2), - ] { - let si = kernel.string_forge().as_ref().intern(name).0; - let sh_c = kernel - .shape_forge() - .as_ref() - .make_shape(math.shape_id(), si); - math.set_shape_id(sh_c); - math.ensure_hash_props().push(Box::new(JsValue::float(val))); - } - - let si_m = kernel.string_forge().intern("Math").0; - let m_shape = kernel.shape_forge().make_shape(global.shape_id(), si_m); - let m_val = - JsValue::from_js_object(kernel.builtin_world().math_object.as_ptr() as *mut JsObject); - global.set_shape_id(m_shape); - global.ensure_hash_props().push(Box::new(m_val)); - global.bump_generation(); -} - -fn bind_json(kernel: &Arc, global: &mut JsObject) { - let json_ptr = kernel.builtin_world().json_object.as_ptr() as *mut JsObject; - let json = unsafe { &mut *json_ptr }; - - bind_method!( - kernel.builtin_world(), - json, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "parse", - crate::builtins::json::json_parse, - 1 - ); - bind_method!( - kernel.builtin_world(), - json, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - "stringify", - crate::builtins::json::json_stringify, - 1 - ); - - let si_j = kernel.string_forge().intern("JSON").0; - let j_shape = kernel.shape_forge().make_shape(global.shape_id(), si_j); - let j_val = - JsValue::from_js_object(kernel.builtin_world().json_object.as_ptr() as *mut JsObject); - global.set_shape_id(j_shape); - global.ensure_hash_props().push(Box::new(j_val)); - global.bump_generation(); -} - -fn bind_date(kernel: &Arc, global: &mut JsObject) { - let ctor_ptr = kernel.builtin_world().date_constructor.as_ptr() as *mut JsObject; - let ctor = unsafe { &mut *ctor_ptr }; - let proto_ptr = kernel.builtin_world().date_proto.as_ptr() as *mut JsObject; - let proto = unsafe { &mut *proto_ptr }; - let sf = kernel.string_forge().as_ref(); - let sh = kernel.shape_forge().as_ref(); - - ctor.set_native_fn(Some(crate::builtins::date::date_constructor as *const ())); - ctor.set_native_arg_count(7); - - bind_method!( - kernel.builtin_world(), - ctor, - sf, - sh, - "now", - crate::builtins::date::date_now, - 0 - ); - bind_method!( - kernel.builtin_world(), - ctor, - sf, - sh, - "parse", - crate::builtins::date::date_parse, - 1 - ); - bind_method!( - kernel.builtin_world(), - ctor, - sf, - sh, - "UTC", - crate::builtins::date::date_utc, - 7 - ); - - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getTime", - crate::builtins::date::date_get_time, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getFullYear", - crate::builtins::date::date_get_full_year, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getMonth", - crate::builtins::date::date_get_month, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getDate", - crate::builtins::date::date_get_date, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getDay", - crate::builtins::date::date_get_day, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getHours", - crate::builtins::date::date_get_hours, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getMinutes", - crate::builtins::date::date_get_minutes, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getSeconds", - crate::builtins::date::date_get_seconds, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getMilliseconds", - crate::builtins::date::date_get_milliseconds, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getUTCFullYear", - crate::builtins::date::date_get_utc_full_year, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getUTCMonth", - crate::builtins::date::date_get_utc_month, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getUTCDate", - crate::builtins::date::date_get_utc_date, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getUTCDay", - crate::builtins::date::date_get_utc_day, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getUTCHours", - crate::builtins::date::date_get_utc_hours, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getUTCMinutes", - crate::builtins::date::date_get_utc_minutes, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getUTCSeconds", - crate::builtins::date::date_get_utc_seconds, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getUTCMilliseconds", - crate::builtins::date::date_get_utc_milliseconds, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "getTimezoneOffset", - crate::builtins::date::date_get_timezone_offset, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "setTime", - crate::builtins::date::date_set_time, - 1 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "setFullYear", - crate::builtins::date::date_set_full_year, - 3 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "setMonth", - crate::builtins::date::date_set_month, - 2 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "setDate", - crate::builtins::date::date_set_date, - 1 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "setHours", - crate::builtins::date::date_set_hours, - 4 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "setMinutes", - crate::builtins::date::date_set_minutes, - 3 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "setSeconds", - crate::builtins::date::date_set_seconds, - 2 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "setMilliseconds", - crate::builtins::date::date_set_milliseconds, - 1 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "toISOString", - crate::builtins::date::date_to_iso_string, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "toJSON", - crate::builtins::date::date_to_json, - 1 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "toString", - crate::builtins::date::date_to_string, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "toDateString", - crate::builtins::date::date_to_date_string, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "toTimeString", - crate::builtins::date::date_to_time_string, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "toUTCString", - crate::builtins::date::date_to_utc_string, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "valueOf", - crate::builtins::date::date_value_of, - 0 - ); - - let si_d = kernel.string_forge().intern("Date").0; - let d_shape = kernel.shape_forge().make_shape(global.shape_id(), si_d); - let d_val = JsValue::from_js_object(ctor_ptr); - global.set_shape_id(d_shape); - global.ensure_hash_props().push(Box::new(d_val)); - global.bump_generation(); -} - -fn bind_set(kernel: &Arc, global: &mut JsObject) { - let ctor_ptr = kernel.builtin_world().set_constructor.as_ptr() as *mut JsObject; - let ctor = unsafe { &mut *ctor_ptr }; - let proto_ptr = kernel.builtin_world().set_proto.as_ptr() as *mut JsObject; - - ctor.set_native_fn(Some(crate::builtins::set::set_constructor as *const ())); - ctor.set_native_arg_count(1); - let proto = unsafe { &mut *proto_ptr }; - let sf = kernel.string_forge().as_ref(); - let sh = kernel.shape_forge().as_ref(); - - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "add", - crate::builtins::set::set_add, - 1 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "has", - crate::builtins::set::set_has, - 1 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "delete", - crate::builtins::set::set_delete, - 1 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "clear", - crate::builtins::set::set_clear, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "size", - crate::builtins::set::set_size, - 0 - ); - - let si_s = kernel.string_forge().intern("Set").0; - let s_shape = kernel.shape_forge().make_shape(global.shape_id(), si_s); - let s_val = JsValue::from_js_object(ctor_ptr); - global.set_shape_id(s_shape); - global.ensure_hash_props().push(Box::new(s_val)); - global.bump_generation(); -} - -fn bind_map(kernel: &Arc, global: &mut JsObject) { - let ctor_ptr = kernel.builtin_world().map_constructor.as_ptr() as *mut JsObject; - let ctor = unsafe { &mut *ctor_ptr }; - let proto_ptr = kernel.builtin_world().map_proto.as_ptr() as *mut JsObject; - - ctor.set_native_fn(Some(crate::builtins::map::map_constructor as *const ())); - ctor.set_native_arg_count(1); - let proto = unsafe { &mut *proto_ptr }; - let sf = kernel.string_forge().as_ref(); - let sh = kernel.shape_forge().as_ref(); - - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "set", - crate::builtins::map::map_set, - 2 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "get", - crate::builtins::map::map_get, - 1 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "has", - crate::builtins::map::map_has, - 1 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "delete", - crate::builtins::map::map_delete, - 1 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "clear", - crate::builtins::map::map_clear, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "size", - crate::builtins::map::map_size, - 0 - ); - - let si_m = kernel.string_forge().intern("Map").0; - let m_shape = kernel.shape_forge().make_shape(global.shape_id(), si_m); - let m_val = JsValue::from_js_object(ctor_ptr); - global.set_shape_id(m_shape); - global.ensure_hash_props().push(Box::new(m_val)); - global.bump_generation(); -} - -fn bind_boolean(kernel: &Arc, global: &mut JsObject) { - let ctor_ptr = kernel.builtin_world().boolean_constructor.as_ptr() as *mut JsObject; - let ctor = unsafe { &mut *ctor_ptr }; - let proto_ptr = kernel.builtin_world().boolean_proto.as_ptr() as *mut JsObject; - let proto = unsafe { &mut *proto_ptr }; - let sf = kernel.string_forge().as_ref(); - let sh = kernel.shape_forge().as_ref(); - - ctor.set_native_fn(Some( - crate::builtins::boolean::boolean_constructor as *const (), - )); - ctor.set_native_arg_count(1); - - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "valueOf", - crate::builtins::boolean::boolean_prototype_value_of, - 0 - ); - bind_method!( - kernel.builtin_world(), - proto, - sf, - sh, - "toString", - crate::builtins::boolean::boolean_prototype_to_string, - 0 - ); - - let si_b = kernel.string_forge().intern("Boolean").0; - let b_shape = kernel.shape_forge().make_shape(global.shape_id(), si_b); - let b_val = JsValue::from_js_object(ctor_ptr); - global.set_shape_id(b_shape); - global.ensure_hash_props().push(Box::new(b_val)); - global.bump_generation(); -} - -fn bind_function(kernel: &Arc) { - let function_methods = FunctionMethods { - call: crate::builtins::function::function_call as *const (), - apply: crate::builtins::function::function_apply as *const (), - bind: crate::builtins::function::function_bind as *const (), - }; - kernel.builtin_world().bind_function_methods( - &function_methods, - kernel.string_forge().as_ref(), - kernel.shape_forge().as_ref(), - ); -} - -pub fn init_kernel_builtins(kernel: &Arc) { - let global_ptr = kernel.global_object().as_ptr() as *mut JsObject; - let global = unsafe { &mut *global_ptr }; - - bind_object(kernel, global); - bind_array(kernel, global); - bind_error(kernel, global); - bind_string(kernel, global); - bind_number(kernel, global); - bind_math(kernel, global); - bind_json(kernel, global); - bind_date(kernel, global); - bind_set(kernel, global); - bind_map(kernel, global); - bind_boolean(kernel, global); - bind_function(kernel); + pub(crate) sub_modules: Vec, + pub(crate) sub_module_constants: Vec>, + pub(crate) saved_bytecode_stack: Vec>, + pub(crate) saved_constants_stack: Vec>, + pub(crate) try_stack: Vec, + pub(crate) exception_value: Option, + pub(crate) pending_exception: Option, + pub(crate) pending_error_kind: Option<&'static str>, } impl Vm { pub fn new() -> Self { let kernel = Arc::new(OxideKernel::new(KernelConfig::minimal())); - init_kernel_builtins(&kernel); + bindings::init_kernel_builtins(&kernel); let obj_proto = P::clone(&kernel.builtin_world().object_proto); Self { regs: [JsValue::undefined(); 256], @@ -1563,7 +473,7 @@ impl Vm { Err("bytecode function calls not yet supported".into()) } - fn unwind(&mut self) -> Result<(), String> { + pub(crate) fn unwind(&mut self) -> Result<(), String> { while let Some(handler) = self.try_stack.pop() { if let Some(finally_pc) = handler.finally_pc { if self.pending_exception.is_none() { @@ -1635,27 +545,19 @@ impl Vm { } OpCode::SUB => { - let l = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); - let r = coercion::to_number(self.regs[b], self.kernel.string_forge().as_ref()); - self.regs[rd] = JsValue::float(l - r); + binary_arith!(self, a, b, rd, -); } OpCode::MUL => { - let l = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); - let r = coercion::to_number(self.regs[b], self.kernel.string_forge().as_ref()); - self.regs[rd] = JsValue::float(l * r); + binary_arith!(self, a, b, rd, *); } OpCode::DIV => { - let l = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); - let r = coercion::to_number(self.regs[b], self.kernel.string_forge().as_ref()); - self.regs[rd] = JsValue::float(l / r); + binary_arith!(self, a, b, rd, /); } OpCode::MOD => { - let l = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); - let r = coercion::to_number(self.regs[b], self.kernel.string_forge().as_ref()); - self.regs[rd] = JsValue::float(l % r); + binary_arith!(self, a, b, rd, %); } OpCode::NEG => { @@ -1775,45 +677,21 @@ impl Vm { if !obj_ptr.is_null() { let obj = unsafe { &*obj_ptr }; if obj.is_function() { - // Always consume extension word for arg_count let ext = self.bytecode[self.pc]; self.pc += 1; let arg_count = (ext & 0xFF) as usize; if obj.native_fn().is_some() { - // Native call - let mut args_buf = [0u8; 257]; - args_buf[0] = this_reg; - for i in 0..arg_count.min(256) { - args_buf[i + 1] = first_arg_reg.wrapping_add(i as u8); + match self.dispatch_native_call( + obj, + callee, + this_reg, + first_arg_reg, + arg_count, + ) { + Ok(()) => continue, + Err(e) => return Err(e), } - let args_slice = &args_buf[..arg_count + 1]; - - let func: NativeFn = - unsafe { std::mem::transmute(obj.native_fn().unwrap()) }; - self.regs[254] = callee; - match func(self, args_slice) { - Ok(val) => self.regs[0] = val, - Err(err_val) => { - let msg = if err_val.is_string() { - self.kernel() - .string_forge() - .lookup(err_val.as_string_index()) - .unwrap_or_else(|| format!("{err_val}")) - } else { - format!("{err_val}") - }; - let error = - crate::builtins::error::create_error(self, &msg); - self.exception_value = Some(error); - self.pending_error_kind = Some("Error"); - match self.unwind() { - Ok(()) => continue, - Err(e) => return Err(e), - } - } - } - continue; } else if obj.sub_module_index() > 0 { // 1-indexed sub_module_index (0 = not a bytecode function) let sub_idx = obj.sub_module_index() as usize - 1; @@ -1930,35 +808,7 @@ impl Vm { self.pc += 1; let arg_count = (ext & 0xFF) as usize; - let mut args_buf = [0u8; 257]; - args_buf[0] = this_reg; - for i in 0..arg_count.min(256) { - args_buf[i + 1] = first_arg_reg.wrapping_add(i as u8); - } - let args_slice = &args_buf[..arg_count + 1]; - - let func: NativeFn = unsafe { std::mem::transmute(obj.native_fn().unwrap()) }; - self.regs[254] = callee; - match func(self, args_slice) { - Ok(val) => self.regs[0] = val, - Err(err_val) => { - let msg = if err_val.is_string() { - self.kernel() - .string_forge() - .lookup(err_val.as_string_index()) - .unwrap_or_else(|| format!("{err_val}")) - } else { - format!("{err_val}") - }; - let error = crate::builtins::error::create_error(self, &msg); - self.exception_value = Some(error); - self.pending_error_kind = Some("Error"); - match self.unwind() { - Ok(()) => continue, - Err(e) => return Err(e), - } - } - } + self.dispatch_native_call(obj, callee, this_reg, first_arg_reg, arg_count)?; } OpCode::NEW_EXPRESSION => { @@ -2323,27 +1173,19 @@ impl Vm { } OpCode::COMPOUND_SUB => { - let l = coercion::to_number(self.regs[rd], self.kernel.string_forge().as_ref()); - let r = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); - self.regs[rd] = JsValue::float(l - r); + compound_arith!(self, rd, a, -); } OpCode::COMPOUND_MUL => { - let l = coercion::to_number(self.regs[rd], self.kernel.string_forge().as_ref()); - let r = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); - self.regs[rd] = JsValue::float(l * r); + compound_arith!(self, rd, a, *); } OpCode::COMPOUND_DIV => { - let l = coercion::to_number(self.regs[rd], self.kernel.string_forge().as_ref()); - let r = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); - self.regs[rd] = JsValue::float(l / r); + compound_arith!(self, rd, a, /); } OpCode::COMPOUND_MOD => { - let l = coercion::to_number(self.regs[rd], self.kernel.string_forge().as_ref()); - let r = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); - self.regs[rd] = JsValue::float(l % r); + compound_arith!(self, rd, a, %); } OpCode::COMPOUND_EXP => { @@ -2448,55 +1290,12 @@ impl Vm { } let obj = unsafe { &mut *obj_ptr }; let prop_name_si = self.regs[b].as_string_index(); - let ext0 = self.bytecode[self.pc]; - let ext1 = self.bytecode[self.pc + 1]; - let ext2 = self.bytecode[self.pc + 2]; - self.pc += 3; - let cached_shape_id = ext0 & 0x00FF_FFFF; - let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64); - - let prop_val = if cached_shape_id != 0 - && cached_shape_id == obj.shape_id() - && cached_ptr != 0 - { - unsafe { *(cached_ptr as *const JsValue) } - } else if let Some(template) = - self.kernel.prop_forge().get_template(obj.shape_id()) - { - if let Some(ptr) = self.template_prop_ptr(obj, &template) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - unsafe { *ptr } - } else { - self.resolve_property(obj, prop_name_si) - .unwrap_or(JsValue::undefined()) - } - } else if let Some(val) = self.resolve_property(obj, prop_name_si) { - let pos = self - .kernel - .shape_forge() - .lookup_position(obj.shape_id(), prop_name_si) - .unwrap_or(0); - if let Some(ptr) = obj.prop_ptr_at(pos) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - } - val - } else { - JsValue::undefined() - }; + let prop_val = member_read_prop!(self, obj, prop_name_si); let n = coercion::to_number(prop_val, self.kernel.string_forge().as_ref()); let new_val = JsValue::float(n + 1.0); - if cached_shape_id != 0 && cached_shape_id == obj.shape_id() && cached_ptr != 0 - { - unsafe { - *(cached_ptr as *mut JsValue) = new_val; - } - } else if let Some(pos) = self + if let Some(pos) = self .kernel .shape_forge() .lookup_position(obj.shape_id(), prop_name_si) @@ -2541,55 +1340,12 @@ impl Vm { } let obj = unsafe { &mut *obj_ptr }; let prop_name_si = self.regs[b].as_string_index(); - let ext0 = self.bytecode[self.pc]; - let ext1 = self.bytecode[self.pc + 1]; - let ext2 = self.bytecode[self.pc + 2]; - self.pc += 3; - let cached_shape_id = ext0 & 0x00FF_FFFF; - let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64); - - let prop_val = if cached_shape_id != 0 - && cached_shape_id == obj.shape_id() - && cached_ptr != 0 - { - unsafe { *(cached_ptr as *const JsValue) } - } else if let Some(template) = - self.kernel.prop_forge().get_template(obj.shape_id()) - { - if let Some(ptr) = self.template_prop_ptr(obj, &template) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - unsafe { *ptr } - } else { - self.resolve_property(obj, prop_name_si) - .unwrap_or(JsValue::undefined()) - } - } else if let Some(val) = self.resolve_property(obj, prop_name_si) { - let pos = self - .kernel - .shape_forge() - .lookup_position(obj.shape_id(), prop_name_si) - .unwrap_or(0); - if let Some(ptr) = obj.prop_ptr_at(pos) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - } - val - } else { - JsValue::undefined() - }; + let prop_val = member_read_prop!(self, obj, prop_name_si); let n = coercion::to_number(prop_val, self.kernel.string_forge().as_ref()); let new_val = JsValue::float(n - 1.0); - if cached_shape_id != 0 && cached_shape_id == obj.shape_id() && cached_ptr != 0 - { - unsafe { - *(cached_ptr as *mut JsValue) = new_val; - } - } else if let Some(pos) = self + if let Some(pos) = self .kernel .shape_forge() .lookup_position(obj.shape_id(), prop_name_si) @@ -2643,22 +1399,7 @@ impl Vm { .unwrap_or(JsValue::undefined()); let n = coercion::to_number(prop_val, self.kernel.string_forge().as_ref()); let new_val = JsValue::float(n + 1.0); - - if let Some(pos) = self - .kernel - .shape_forge() - .lookup_position(obj.shape_id(), prop_name_si) - { - obj.set_prop_at(pos, new_val); - } else { - let new_shape_id = self - .kernel - .shape_forge() - .make_shape(obj.shape_id(), prop_name_si); - obj.set_shape_id(new_shape_id); - obj.push_prop(new_val); - obj.bump_generation(); - }; + set_or_create_prop!(self, obj, prop_name_si, new_val); self.regs[b] = new_val; } @@ -2678,22 +1419,7 @@ impl Vm { .unwrap_or(JsValue::undefined()); let n = coercion::to_number(prop_val, self.kernel.string_forge().as_ref()); let new_val = JsValue::float(n - 1.0); - - if let Some(pos) = self - .kernel - .shape_forge() - .lookup_position(obj.shape_id(), prop_name_si) - { - obj.set_prop_at(pos, new_val); - } else { - let new_shape_id = self - .kernel - .shape_forge() - .make_shape(obj.shape_id(), prop_name_si); - obj.set_shape_id(new_shape_id); - obj.push_prop(new_val); - obj.bump_generation(); - }; + set_or_create_prop!(self, obj, prop_name_si, new_val); self.regs[b] = new_val; }