From 4ec588470058c2ca17f9f414b6ec3ff00efbade0 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Wed, 22 Jan 2025 11:06:53 -0800 Subject: [PATCH] Make the HostHooks shareable --- core/engine/src/builtins/date/mod.rs | 80 +++++++++++++---------- core/engine/src/context/hooks.rs | 3 +- core/engine/src/context/mod.rs | 16 ++--- core/engine/src/object/builtins/jsdate.rs | 2 +- examples/src/bin/jsdate.rs | 3 +- 5 files changed, 58 insertions(+), 46 deletions(-) diff --git a/core/engine/src/builtins/date/mod.rs b/core/engine/src/builtins/date/mod.rs index dbf5051b7de..d7acbd8e241 100644 --- a/core/engine/src/builtins/date/mod.rs +++ b/core/engine/src/builtins/date/mod.rs @@ -213,7 +213,7 @@ impl BuiltInConstructor for Date { // b. Return ToDateString(now). return Ok(JsValue::from(to_date_string_t( now as f64, - context.host_hooks(), + context.host_hooks().as_ref(), ))); } @@ -222,7 +222,7 @@ impl BuiltInConstructor for Date { // 3. If numberOfArgs = 0, then [] => { // a. Let dv be the time value (UTC) identifying the current time. - Self::utc_now(context.host_hooks()) + Self::utc_now(context.host_hooks().as_ref()) } // 4. Else if numberOfArgs = 1, then // a. Let value be values[0]. @@ -243,7 +243,7 @@ impl BuiltInConstructor for Date { if let Some(v) = v.as_string() { // 1. Assert: The next step never returns an abrupt completion because v is a String. // 2. Let tv be the result of parsing v as a date, in exactly the same manner as for the parse method (21.4.3.2). - let tv = parse_date(v, context.host_hooks()); + let tv = parse_date(v, context.host_hooks().as_ref()); if let Some(tv) = tv { tv as f64 } else { @@ -296,7 +296,7 @@ impl BuiltInConstructor for Date { let final_date = make_date(make_day(yr, m, dt), make_time(h, min, s, milli)); // k. Let dv be TimeClip(UTC(finalDate)). - Self(time_clip(utc_t(final_date, context.host_hooks()))) + Self(time_clip(utc_t(final_date, context.host_hooks().as_ref()))) } }; @@ -343,7 +343,8 @@ impl Date { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse pub(crate) fn parse(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { let date = args.get_or_undefined(0).to_string(context)?; - Ok(parse_date(&date, context.host_hooks()).map_or(JsValue::from(f64::NAN), JsValue::from)) + Ok(parse_date(&date, context.host_hooks().as_ref()) + .map_or(JsValue::from(f64::NAN), JsValue::from)) } /// `Date.UTC()` @@ -430,7 +431,7 @@ impl Date { // 5. Return DateFromTime(LocalTime(t)). Ok(JsValue::from(date_from_time(local_time( t, - context.host_hooks(), + context.host_hooks().as_ref(), )))) } else { // 5. Return DateFromTime(t). @@ -467,7 +468,10 @@ impl Date { if LOCAL { // 5. Return WeekDay(LocalTime(t)). - Ok(JsValue::from(week_day(local_time(t, context.host_hooks())))) + Ok(JsValue::from(week_day(local_time( + t, + context.host_hooks().as_ref(), + )))) } else { // 5. Return WeekDay(t). Ok(JsValue::from(week_day(t))) @@ -506,7 +510,7 @@ impl Date { // 5. Return YearFromTime(LocalTime(t)) - 1900𝔽. Ok(JsValue::from( - year_from_time(local_time(t, context.host_hooks())) - 1900, + year_from_time(local_time(t, context.host_hooks().as_ref())) - 1900, )) } @@ -540,7 +544,7 @@ impl Date { // 5. Return YearFromTime(LocalTime(t)). Ok(JsValue::from(year_from_time(local_time( t, - context.host_hooks(), + context.host_hooks().as_ref(), )))) } else { // 5. Return YearFromTime(t). @@ -578,7 +582,7 @@ impl Date { // 5. Return HourFromTime(LocalTime(t)). Ok(JsValue::from(hour_from_time(local_time( t, - context.host_hooks(), + context.host_hooks().as_ref(), )))) } else { // 5. Return HourFromTime(t). @@ -616,7 +620,7 @@ impl Date { // 5. Return msFromTime(LocalTime(t)). Ok(JsValue::from(ms_from_time(local_time( t, - context.host_hooks(), + context.host_hooks().as_ref(), )))) } else { // 5. Return msFromTime(t). @@ -654,7 +658,7 @@ impl Date { // 5. Return MinFromTime(LocalTime(t)). Ok(JsValue::from(min_from_time(local_time( t, - context.host_hooks(), + context.host_hooks().as_ref(), )))) } else { // 5. Return MinFromTime(t). @@ -693,7 +697,7 @@ impl Date { // 5. Return MonthFromTime(LocalTime(t)). Ok(JsValue::from(month_from_time(local_time( t, - context.host_hooks(), + context.host_hooks().as_ref(), )))) } else { // 5. Return MonthFromTime(t). @@ -731,7 +735,7 @@ impl Date { // 5. Return SecFromTime(LocalTime(t)). Ok(JsValue::from(sec_from_time(local_time( t, - context.host_hooks(), + context.host_hooks().as_ref(), )))) } else { // 5. Return SecFromTime(t). @@ -797,7 +801,7 @@ impl Date { // 5. Return (t - LocalTime(t)) / msPerMinute. Ok(JsValue::from( - (t - local_time(t, context.host_hooks())) / MS_PER_MINUTE, + (t - local_time(t, context.host_hooks().as_ref())) / MS_PER_MINUTE, )) } @@ -840,7 +844,7 @@ impl Date { if LOCAL { // 6. Set t to LocalTime(t). - t = local_time(t, context.host_hooks()); + t = local_time(t, context.host_hooks().as_ref()); } // 7. Let newDate be MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t)). @@ -851,7 +855,7 @@ impl Date { let u = if LOCAL { // 8. Let u be TimeClip(UTC(newDate)). - time_clip(utc_t(new_date, context.host_hooks())) + time_clip(utc_t(new_date, context.host_hooks().as_ref())) } else { // 8. Let v be TimeClip(newDate). time_clip(new_date) @@ -903,7 +907,7 @@ impl Date { if t.is_nan() { 0.0 } else { - local_time(t, context.host_hooks()) + local_time(t, context.host_hooks().as_ref()) } } else { // 4. If t is NaN, set t to +0𝔽. @@ -936,7 +940,7 @@ impl Date { let u = if LOCAL { // 9. Let u be TimeClip(UTC(newDate)). - time_clip(utc_t(new_date, context.host_hooks())) + time_clip(utc_t(new_date, context.host_hooks().as_ref())) } else { // 9. Let u be TimeClip(newDate). time_clip(new_date) @@ -1004,7 +1008,7 @@ impl Date { if LOCAL { // 9. Set t to LocalTime(t). - t = local_time(t, context.host_hooks()); + t = local_time(t, context.host_hooks().as_ref()); } // 10. If min is not present, let m be MinFromTime(t). @@ -1021,7 +1025,7 @@ impl Date { let u = if LOCAL { // 14. Let u be TimeClip(UTC(date)). - time_clip(utc_t(date, context.host_hooks())) + time_clip(utc_t(date, context.host_hooks().as_ref())) } else { // 14. Let u be TimeClip(date). time_clip(date) @@ -1077,7 +1081,7 @@ impl Date { if LOCAL { // 6. Set t to LocalTime(t). - t = local_time(t, context.host_hooks()); + t = local_time(t, context.host_hooks().as_ref()); } // 7. Let time be MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms). @@ -1090,7 +1094,10 @@ impl Date { let u = if LOCAL { // 8. Let u be TimeClip(UTC(MakeDate(Day(t), time))). - time_clip(utc_t(make_date(day(t), time), context.host_hooks())) + time_clip(utc_t( + make_date(day(t), time), + context.host_hooks().as_ref(), + )) } else { // 8. Let u be TimeClip(MakeDate(Day(t), time)). time_clip(make_date(day(t), time)) @@ -1152,7 +1159,7 @@ impl Date { if LOCAL { // 8. Set t to LocalTime(t). - t = local_time(t, context.host_hooks()); + t = local_time(t, context.host_hooks().as_ref()); } // 9. If sec is not present, let s be SecFromTime(t). @@ -1166,7 +1173,7 @@ impl Date { let u = if LOCAL { // 12. Let u be TimeClip(UTC(date)). - time_clip(utc_t(date, context.host_hooks())) + time_clip(utc_t(date, context.host_hooks().as_ref())) } else { // 12. Let u be TimeClip(date). time_clip(date) @@ -1226,7 +1233,7 @@ impl Date { // 7. Set t to LocalTime(t). if LOCAL { - t = local_time(t, context.host_hooks()); + t = local_time(t, context.host_hooks().as_ref()); } // 8. If date is not present, let dt be DateFromTime(t). @@ -1240,7 +1247,7 @@ impl Date { let u = if LOCAL { // 10. Let u be TimeClip(UTC(newDate)). - time_clip(utc_t(new_date, context.host_hooks())) + time_clip(utc_t(new_date, context.host_hooks().as_ref())) } else { // 10. Let u be TimeClip(newDate). time_clip(new_date) @@ -1299,7 +1306,7 @@ impl Date { // 7. Set t to LocalTime(t). if LOCAL { - t = local_time(t, context.host_hooks()); + t = local_time(t, context.host_hooks().as_ref()); } // 8. If ms is not present, let milli be msFromTime(t). @@ -1313,7 +1320,7 @@ impl Date { let u = if LOCAL { // 10. Let u be TimeClip(UTC(date)). - time_clip(utc_t(date, context.host_hooks())) + time_clip(utc_t(date, context.host_hooks().as_ref())) } else { // 10. Let u be TimeClip(date). time_clip(date) @@ -1373,7 +1380,7 @@ impl Date { let t = if t.is_nan() { 0.0 } else { - local_time(t, context.host_hooks()) + local_time(t, context.host_hooks().as_ref()) }; // 6. Let yyyy be MakeFullYear(y). @@ -1386,7 +1393,7 @@ impl Date { let date = make_date(d, time_within_day(t)); // 9. Let u be TimeClip(UTC(date)). - let u = time_clip(utc_t(date, context.host_hooks())); + let u = time_clip(utc_t(date, context.host_hooks().as_ref())); let mut date_mut = this .as_object() @@ -1475,7 +1482,7 @@ impl Date { }; // 5. Let t be LocalTime(tv). - let t = local_time(tv, context.host_hooks()); + let t = local_time(tv, context.host_hooks().as_ref()); // 6. Return DateString(t). Ok(JsValue::from(date_string(t))) @@ -1668,7 +1675,10 @@ impl Date { .0; // 4. Return ToDateString(tv). - Ok(JsValue::from(to_date_string_t(tv, context.host_hooks()))) + Ok(JsValue::from(to_date_string_t( + tv, + context.host_hooks().as_ref(), + ))) } /// [`Date.prototype.toTimeString()`][spec]. @@ -1701,12 +1711,12 @@ impl Date { } // 5. Let t be LocalTime(tv). - let t = local_time(tv, context.host_hooks()); + let t = local_time(tv, context.host_hooks().as_ref()); // 6. Return the string-concatenation of TimeString(t) and TimeZoneString(tv). Ok(JsValue::from(js_string!( &time_string(t), - &time_zone_string(t, context.host_hooks()) + &time_zone_string(t, context.host_hooks().as_ref()) ))) } diff --git a/core/engine/src/context/hooks.rs b/core/engine/src/context/hooks.rs index e30b8ea39ed..4d930b62c65 100644 --- a/core/engine/src/context/hooks.rs +++ b/core/engine/src/context/hooks.rs @@ -19,6 +19,7 @@ use time::{OffsetDateTime, UtcOffset}; /// need to be redefined: /// /// ``` +/// use std::rc::Rc; /// use boa_engine::{ /// context::{Context, ContextBuilder, HostHooks}, /// realm::Realm, @@ -42,7 +43,7 @@ use time::{OffsetDateTime, UtcOffset}; /// } /// } /// -/// let context = &mut ContextBuilder::new().host_hooks(&Hooks).build().unwrap(); +/// let context = &mut ContextBuilder::new().host_hooks(Rc::new(Hooks)).build().unwrap(); /// let result = context.eval(Source::from_bytes(r#"eval("let a = 5")"#)); /// assert_eq!( /// result.unwrap_err().to_string(), diff --git a/core/engine/src/context/mod.rs b/core/engine/src/context/mod.rs index ccd57b4065c..d4d3e5663d1 100644 --- a/core/engine/src/context/mod.rs +++ b/core/engine/src/context/mod.rs @@ -111,7 +111,7 @@ pub struct Context { #[cfg(feature = "intl")] intl_provider: icu::IntlProvider, - host_hooks: &'static dyn HostHooks, + host_hooks: Rc, job_executor: Rc, @@ -530,7 +530,7 @@ impl Context { /// Create a new Realm with the default global bindings. pub fn create_realm(&mut self) -> JsResult { - let realm = Realm::create(self.host_hooks, &self.root_shape)?; + let realm = Realm::create(self.host_hooks.as_ref(), &self.root_shape)?; let old_realm = self.enter_realm(realm); @@ -549,8 +549,8 @@ impl Context { /// Gets the host hooks. #[inline] #[must_use] - pub fn host_hooks(&self) -> &'static dyn HostHooks { - self.host_hooks + pub fn host_hooks(&self) -> Rc { + self.host_hooks.clone() } /// Gets the job executor. @@ -887,7 +887,7 @@ impl Context { #[derive(Default)] pub struct ContextBuilder { interner: Option, - host_hooks: Option<&'static dyn HostHooks>, + host_hooks: Option>, job_executor: Option>, module_loader: Option>, can_block: bool, @@ -1021,7 +1021,7 @@ impl ContextBuilder { /// /// [`Host Hooks`]: https://tc39.es/ecma262/#sec-host-hooks-summary #[must_use] - pub fn host_hooks(mut self, host_hooks: &'static H) -> Self { + pub fn host_hooks(mut self, host_hooks: Rc) -> Self { self.host_hooks = Some(host_hooks); self } @@ -1088,8 +1088,8 @@ impl ContextBuilder { let root_shape = RootShape::default(); - let host_hooks = self.host_hooks.unwrap_or(&DefaultHooks); - let realm = Realm::create(host_hooks, &root_shape)?; + let host_hooks = self.host_hooks.unwrap_or(Rc::new(DefaultHooks)); + let realm = Realm::create(host_hooks.as_ref(), &root_shape)?; let vm = Vm::new(realm); let module_loader: Rc = if let Some(loader) = self.module_loader { diff --git a/core/engine/src/object/builtins/jsdate.rs b/core/engine/src/object/builtins/jsdate.rs index 1000c39e0a9..7d481385d80 100644 --- a/core/engine/src/object/builtins/jsdate.rs +++ b/core/engine/src/object/builtins/jsdate.rs @@ -45,7 +45,7 @@ impl JsDate { let inner = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), prototype, - Date::utc_now(context.host_hooks()), + Date::utc_now(context.host_hooks().as_ref()), ); Self { inner } diff --git a/examples/src/bin/jsdate.rs b/examples/src/bin/jsdate.rs index 89848e60946..68555868c2c 100644 --- a/examples/src/bin/jsdate.rs +++ b/examples/src/bin/jsdate.rs @@ -1,6 +1,7 @@ use boa_engine::{ context::HostHooks, js_string, object::builtins::JsDate, Context, JsResult, JsValue, }; +use std::rc::Rc; struct CustomTimezone; @@ -15,7 +16,7 @@ impl HostHooks for CustomTimezone { fn main() -> JsResult<()> { let context = &mut Context::builder() - .host_hooks(&CustomTimezone) + .host_hooks(Rc::new(CustomTimezone)) .build() .unwrap();