| 
									
										
										
										
											2021-06-15 22:16:17 +03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/FinalizationRegistry.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace JS { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-27 21:48:34 +02:00
										 |  |  | FinalizationRegistry* FinalizationRegistry::create(GlobalObject& global_object, FunctionObject& cleanup_callback) | 
					
						
							| 
									
										
										
										
											2021-06-15 22:16:17 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-06-19 23:21:08 +01:00
										 |  |  |     return global_object.heap().allocate<FinalizationRegistry>(global_object, cleanup_callback, *global_object.finalization_registry_prototype()); | 
					
						
							| 
									
										
										
										
											2021-06-15 22:16:17 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-27 21:48:34 +02:00
										 |  |  | FinalizationRegistry::FinalizationRegistry(FunctionObject& cleanup_callback, Object& prototype) | 
					
						
							| 
									
										
										
										
											2021-06-15 22:16:17 +03:00
										 |  |  |     : Object(prototype) | 
					
						
							|  |  |  |     , WeakContainer(heap()) | 
					
						
							|  |  |  |     , m_cleanup_callback(&cleanup_callback) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FinalizationRegistry::~FinalizationRegistry() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FinalizationRegistry::add_finalization_record(Cell& target, Value held_value, Object* unregister_token) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VERIFY(!held_value.is_empty()); | 
					
						
							|  |  |  |     m_records.append({ &target, held_value, unregister_token }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool FinalizationRegistry::remove_by_token(Object& unregister_token) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto removed = false; | 
					
						
							|  |  |  |     for (auto it = m_records.begin(); it != m_records.end(); ++it) { | 
					
						
							|  |  |  |         if (it->unregister_token == &unregister_token) { | 
					
						
							|  |  |  |             it.remove(m_records); | 
					
						
							|  |  |  |             removed = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return removed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-11 12:02:38 +02:00
										 |  |  | void FinalizationRegistry::remove_swept_cells(Badge<Heap>, Span<Cell*> cells) | 
					
						
							| 
									
										
										
										
											2021-06-15 22:16:17 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-06-27 22:39:48 +02:00
										 |  |  |     auto any_cells_were_swept = false; | 
					
						
							| 
									
										
										
										
											2021-09-11 12:02:38 +02:00
										 |  |  |     for (auto* cell : cells) { | 
					
						
							| 
									
										
										
										
											2021-06-15 22:16:17 +03:00
										 |  |  |         for (auto& record : m_records) { | 
					
						
							|  |  |  |             if (record.target != cell) | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             record.target = nullptr; | 
					
						
							| 
									
										
										
										
											2021-06-27 22:39:48 +02:00
										 |  |  |             any_cells_were_swept = true; | 
					
						
							| 
									
										
										
										
											2021-06-15 22:16:17 +03:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-27 22:39:48 +02:00
										 |  |  |     if (any_cells_were_swept) | 
					
						
							| 
									
										
										
										
											2021-06-15 22:16:17 +03:00
										 |  |  |         vm().enqueue_finalization_registry_cleanup_job(*this); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 9.13 CleanupFinalizationRegistry ( finalizationRegistry ), https://tc39.es/ecma262/#sec-cleanup-finalization-registry
 | 
					
						
							| 
									
										
										
										
											2021-06-27 21:48:34 +02:00
										 |  |  | void FinalizationRegistry::cleanup(FunctionObject* callback) | 
					
						
							| 
									
										
										
										
											2021-06-15 22:16:17 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     auto& vm = this->vm(); | 
					
						
							|  |  |  |     auto cleanup_callback = callback ?: m_cleanup_callback; | 
					
						
							|  |  |  |     for (auto it = m_records.begin(); it != m_records.end(); ++it) { | 
					
						
							|  |  |  |         if (it->target != nullptr) | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         (void)vm.call(*cleanup_callback, js_undefined(), it->held_value); | 
					
						
							|  |  |  |         it.remove(m_records); | 
					
						
							|  |  |  |         if (vm.exception()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FinalizationRegistry::visit_edges(Cell::Visitor& visitor) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-09-11 14:05:12 +02:00
										 |  |  |     Base::visit_edges(visitor); | 
					
						
							| 
									
										
										
										
											2021-06-15 22:16:17 +03:00
										 |  |  |     visitor.visit(m_cleanup_callback); | 
					
						
							|  |  |  |     for (auto& record : m_records) { | 
					
						
							|  |  |  |         visitor.visit(record.held_value); | 
					
						
							|  |  |  |         visitor.visit(record.unregister_token); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |