From fb7b1e18bb207b4272572d8354eb7786128cc014 Mon Sep 17 00:00:00 2001 From: Carter Snook Date: Sun, 5 Nov 2023 01:27:50 -0600 Subject: [PATCH 1/3] feat: better Agent <=> Realm relationship We now pass around realms as identifier which allows us to avoid locking thanks to AapoAlas's idea. --- nova_vm/src/ecmascript/execution/realm.rs | 78 ++++++++++------------- 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/nova_vm/src/ecmascript/execution/realm.rs b/nova_vm/src/ecmascript/execution/realm.rs index 37466bec..c5cd336b 100644 --- a/nova_vm/src/ecmascript/execution/realm.rs +++ b/nova_vm/src/ecmascript/execution/realm.rs @@ -34,8 +34,6 @@ impl<'ctx, 'host> RealmIdentifier<'ctx, 'host> { /// https://tc39.es/ecma262/#sec-code-realms #[derive(Debug)] pub struct Realm<'ctx, 'host> { - pub agent: Rc>>, - // NOTE: We will need an rng here at some point. // [[Intrinsics]] @@ -50,21 +48,22 @@ pub struct Realm<'ctx, 'host> { /// [[HostDefined]] pub host_defined: Option>>, // TODO: [[TemplateMap]], [[LoadedModules]] + _marker: PhantomData<(&'ctx (), &'host ())>, } impl<'ctx, 'host> Realm<'ctx, 'host> { /// 9.3.1 CreateRealm ( ), https://tc39.es/ecma262/#sec-createrealm - fn create(agent: Rc>>) -> RealmIdentifier<'ctx, 'host> { + fn create(agent: &mut Agent<'ctx, 'host>) -> RealmIdentifier<'ctx, 'host> { // TODO: implement spec let realm = Self { - agent: agent.clone(), global_env: GlobalEnvironmentIndex::from_u32_index(0), global_object: Object::Object(ObjectIndex::from_u32_index(0)), host_defined: None, intrinsics: Intrinsics::default(), + _marker: PhantomData::default(), }; - agent.borrow_mut().heap.add_realm(realm) + agent.heap.add_realm(realm) } pub(crate) fn intrinsics(&self) -> &Intrinsics { @@ -73,18 +72,18 @@ impl<'ctx, 'host> Realm<'ctx, 'host> { /// 9.3.3 SetRealmGlobalObject ( realmRec, globalObj, thisValue ), https://tc39.es/ecma262/#sec-setrealmglobalobject pub(crate) fn set_global_object( - &mut self, + agent: &mut Agent<'ctx, 'host>, + realm_id: RealmIdentifier<'ctx, 'host>, global_object: Option, this_value: Option, ) { // 1. If globalObj is undefined, then let global_object = global_object.unwrap_or_else(|| { // a. Let intrinsics be realmRec.[[Intrinsics]]. - let intrinsics = &self.intrinsics; + let intrinsics = &agent.get_realm(realm_id).intrinsics; // b. Set globalObj to OrdinaryObjectCreate(intrinsics.[[%Object.prototype%]]). Object::Object( - self.agent - .borrow_mut() + agent .heap .create_object_with_prototype(intrinsics.object_prototype()), ) @@ -96,14 +95,13 @@ impl<'ctx, 'host> Realm<'ctx, 'host> { let this_value = this_value.unwrap_or(global_object); // 4. Set realmRec.[[GlobalObject]] to globalObj. - self.global_object = global_object; + agent.heap.get_realm_mut(realm_id).global_object = global_object; // 5. Let newGlobalEnv be NewGlobalEnvironment(globalObj, thisValue). let new_global_env = GlobalEnvironment::new(global_object, this_value); + // 6. Set realmRec.[[GlobalEnv]] to newGlobalEnv. - self.global_env = self - .agent - .borrow_mut() + agent.heap.get_realm_mut(realm_id).global_env = agent .heap .environments .push_global_environment(new_global_env); @@ -113,32 +111,34 @@ impl<'ctx, 'host> Realm<'ctx, 'host> { /// 9.3.4 SetDefaultGlobalBindings ( realmRec ) /// https://tc39.es/ecma262/#sec-setdefaultglobalbindings pub(crate) fn set_default_global_bindings( - &mut self, - agent: Rc>>, + agent: &mut Agent, + realm_id: RealmIdentifier, ) -> JsResult { // 1. Let global be realmRec.[[GlobalObject]]. - let global = self.global_object; + // NOTE: We define this later to ensure reference safety. // 2. For each property of the Global Object specified in clause 19, do + // a. Let name be the String value of the property name. - let name = - PropertyKey::try_from(Value::from_str(&mut agent.borrow_mut().heap, "globalThis")) - .unwrap(); + let name = PropertyKey::try_from(Value::from_str(&mut agent.heap, "globalThis")).unwrap(); + // b. Let desc be the fully populated data Property Descriptor for the property, containing the specified attributes for the property. For properties listed in 19.2, 19.3, or 19.4 the value of the [[Value]] attribute is the corresponding intrinsic object from realmRec. + let global_env = agent.heap.get_realm(realm_id).global_env; let desc = PropertyDescriptor { value: Some( agent - .borrow() .heap .environments - .get_global_environment(self.global_env) + .get_global_environment(global_env) .global_this_value .into_value(), ), ..Default::default() }; + // c. Perform ? DefinePropertyOrThrow(global, name, desc). - global.define_property_or_throw(&mut agent.borrow_mut(), name, desc)?; + let global = agent.heap.get_realm(realm_id).global_object; + global.define_property_or_throw(agent, name, desc)?; // TODO: Actually do other properties aside from globalThis. @@ -148,16 +148,17 @@ impl<'ctx, 'host> Realm<'ctx, 'host> { /// 9.6 InitializeHostDefinedRealm ( ), https://tc39.es/ecma262/#sec-initializehostdefinedrealm pub fn initialize_host_defined_realm( - agent: Rc>>, + agent: &mut Agent<'ctx, 'host>, + realm_id: RealmIdentifier<'ctx, 'host>, create_global_object: Option, create_global_this_value: Option, initialize_global_object: Option, ) where - F: FnOnce(&mut Realm<'ctx, 'host>) -> Object, - Init: FnOnce(Rc>>, Object), + F: FnOnce(&mut Realm) -> Object, + Init: FnOnce(&mut Agent, Object), { // 1. Let realm be CreateRealm(). - let realm = Self::create(agent.clone()); + let realm = Realm::create(agent); // 2. Let newContext be a new execution context. let mut new_context = ExecutionContext::new(); @@ -172,38 +173,29 @@ impl<'ctx, 'host> Realm<'ctx, 'host> { // No-op // 6. Push newContext onto the execution context stack; newContext is now the running execution context. - agent.borrow_mut().execution_context_stack.push(new_context); + agent.execution_context_stack.push(new_context); // 7. If the host requires use of an exotic object to serve as realm's global object, // let global be such an object created in a host-defined manner. // Otherwise, let global be undefined, indicating that an ordinary object should be created as the global object. - let global = create_global_this_value.map(|create_global_this_value| { - create_global_this_value(agent.borrow_mut().current_realm_mut()) - }); + let global = create_global_this_value + .map(|create_global_this_value| create_global_this_value(agent.current_realm_mut())); // 8. If the host requires that the this binding in realm's global scope return an object other than the global object, // let thisValue be such an object created in a host-defined manner. // Otherwise, let thisValue be undefined, indicating that realm's global this binding should be the global object. - let this_value = create_global_object.map(|create_global_object| { - create_global_object(agent.borrow_mut().current_realm_mut()) - }); + let this_value = create_global_object + .map(|create_global_object| create_global_object(agent.current_realm_mut())); // 9. Perform SetRealmGlobalObject(realm, global, thisValue). - agent - .borrow_mut() - .get_realm_mut(realm) - .set_global_object(global, this_value); + Realm::set_global_object(agent, realm_id, global, this_value); // 10. Let globalObj be ? SetDefaultGlobalBindings(realm). - let global_obj = agent - .borrow_mut() - .get_realm_mut(realm) - .set_default_global_bindings(agent.clone()) - .unwrap(); + let global_object = Realm::set_default_global_bindings(agent, realm_id).unwrap(); // 11. Create any host-defined global object properties on globalObj. if let Some(initialize_global_object) = initialize_global_object { - initialize_global_object(agent, global_obj); + initialize_global_object(agent, global_object); }; // 12. Return UNUSED. From 09b3d26ff7dd8cc26952eb869c36383fb9c5c501 Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Fri, 24 Nov 2023 20:21:25 +0200 Subject: [PATCH 2/3] Fix --- nova_vm/src/ecmascript/execution/realm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova_vm/src/ecmascript/execution/realm.rs b/nova_vm/src/ecmascript/execution/realm.rs index 1a9a56de..27bb85aa 100644 --- a/nova_vm/src/ecmascript/execution/realm.rs +++ b/nova_vm/src/ecmascript/execution/realm.rs @@ -55,7 +55,7 @@ impl<'ctx, 'host> Realm<'ctx, 'host> { fn create(agent: &mut Agent<'ctx, 'host>) -> RealmIdentifier<'ctx, 'host> { // TODO: implement spec let realm = Self { - global_env: GlobalEnvironmentIndex::from_u32_index(0), + global_env: GlobalEnvironmentIndex::from_index(0), global_object: Object::Object(ObjectIndex::from_u32_index(0)), host_defined: None, intrinsics: Intrinsics::default(), @@ -97,7 +97,7 @@ impl<'ctx, 'host> Realm<'ctx, 'host> { agent.heap.get_realm_mut(realm_id).global_object = global_object; // 5. Let newGlobalEnv be NewGlobalEnvironment(globalObj, thisValue). - let new_global_env = GlobalEnvironment::new(global_object, this_value); + let new_global_env = GlobalEnvironment::new(&mut agent, global_object, this_value); // 6. Set realmRec.[[GlobalEnv]] to newGlobalEnv. agent.heap.get_realm_mut(realm_id).global_env = agent From 8f5e39be8469bc8de659ea086d04c33f00b24086 Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Fri, 24 Nov 2023 20:23:54 +0200 Subject: [PATCH 3/3] Fix 2 --- nova_vm/src/ecmascript/execution/realm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova_vm/src/ecmascript/execution/realm.rs b/nova_vm/src/ecmascript/execution/realm.rs index 27bb85aa..9a6d49b4 100644 --- a/nova_vm/src/ecmascript/execution/realm.rs +++ b/nova_vm/src/ecmascript/execution/realm.rs @@ -97,7 +97,7 @@ impl<'ctx, 'host> Realm<'ctx, 'host> { agent.heap.get_realm_mut(realm_id).global_object = global_object; // 5. Let newGlobalEnv be NewGlobalEnvironment(globalObj, thisValue). - let new_global_env = GlobalEnvironment::new(&mut agent, global_object, this_value); + let new_global_env = GlobalEnvironment::new(agent, global_object, this_value); // 6. Set realmRec.[[GlobalEnv]] to newGlobalEnv. agent.heap.get_realm_mut(realm_id).global_env = agent