mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
Indexeddb: Cache IDBCursor.key conversion to preserve object identity (#44161)
Testing: Covered by idbcursor-key.any.html test. part of https://github.com/servo/servo/issues/40983 --------- Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
This commit is contained in:
@@ -56,6 +56,10 @@ pub(crate) struct IDBCursor {
|
||||
/// <https://www.w3.org/TR/IndexedDB-3/#cursor-key>
|
||||
#[no_trace]
|
||||
key: DomRefCell<Option<IndexedDBKeyType>>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
cached_key: DomRefCell<Option<Heap<JSVal>>>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
cached_primary_key: DomRefCell<Option<Heap<JSVal>>>,
|
||||
/// <https://www.w3.org/TR/IndexedDB-3/#cursor-value>
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
value: Heap<JSVal>,
|
||||
@@ -89,6 +93,8 @@ impl IDBCursor {
|
||||
direction,
|
||||
position: DomRefCell::new(None),
|
||||
key: DomRefCell::new(None),
|
||||
cached_key: DomRefCell::new(None),
|
||||
cached_primary_key: DomRefCell::new(None),
|
||||
value: Heap::default(),
|
||||
got_value: Cell::new(got_value),
|
||||
object_store_position: DomRefCell::new(None),
|
||||
@@ -124,15 +130,30 @@ impl IDBCursor {
|
||||
}
|
||||
|
||||
fn set_position(&self, position: Option<IndexedDBKeyType>) {
|
||||
let changed = *self.position.borrow() != position;
|
||||
*self.position.borrow_mut() = position;
|
||||
if changed {
|
||||
*self.cached_primary_key.borrow_mut() = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_key(&self, key: Option<IndexedDBKeyType>) {
|
||||
let key_changed = {
|
||||
let current_key = self.key.borrow();
|
||||
current_key.as_ref() != key.as_ref()
|
||||
};
|
||||
*self.key.borrow_mut() = key;
|
||||
if key_changed {
|
||||
*self.cached_key.borrow_mut() = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_object_store_position(&self, object_store_position: Option<IndexedDBKeyType>) {
|
||||
let changed = *self.object_store_position.borrow() != object_store_position;
|
||||
*self.object_store_position.borrow_mut() = object_store_position;
|
||||
if changed {
|
||||
*self.cached_primary_key.borrow_mut() = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_request(&self, request: &IDBRequest) {
|
||||
@@ -172,18 +193,50 @@ impl IDBCursorMethods<crate::DomTypeHolder> for IDBCursor {
|
||||
|
||||
/// <https://www.w3.org/TR/IndexedDB-3/#dom-idbcursor-key>
|
||||
fn Key(&self, cx: &mut JSContext, mut value: MutableHandleValue) {
|
||||
// The key getter steps are to return the result of converting a key to a value with the cursor’s current key.
|
||||
//
|
||||
// NOTE: If key returns an object (e.g. a Date or Array), it returns the
|
||||
// same object instance every time it is inspected, until the cursor’s key is changed.
|
||||
// This means that if the object is modified, those modifications will be seen by
|
||||
// anyone inspecting the value of the cursor. However modifying such an object does not
|
||||
// modify the contents of the database.
|
||||
if let Some(cached) = &*self.cached_key.borrow() {
|
||||
value.set(cached.get());
|
||||
return;
|
||||
}
|
||||
|
||||
match self.key.borrow().as_ref() {
|
||||
Some(key) => key_type_to_jsval(cx, key, value),
|
||||
Some(key) => key_type_to_jsval(cx, key, value.reborrow()),
|
||||
None => value.set(UndefinedValue()),
|
||||
}
|
||||
|
||||
*self.cached_key.borrow_mut() = Some(Heap::default());
|
||||
self.cached_key.borrow().as_ref().unwrap().set(value.get());
|
||||
}
|
||||
|
||||
/// <https://www.w3.org/TR/IndexedDB-3/#dom-idbcursor-primarykey>
|
||||
fn PrimaryKey(&self, cx: &mut JSContext, mut value: MutableHandleValue) {
|
||||
// NOTE: If primaryKey returns an object (e.g. a Date or Array),
|
||||
// it returns the same object instance every time it is inspected,
|
||||
// until the cursor’s effective key is changed. This means that if the object is modified,
|
||||
// those modifications will be seen by anyone inspecting the value of the cursor.
|
||||
// However modifying such an object does not modify the contents of the database.
|
||||
if let Some(cached) = &*self.cached_primary_key.borrow() {
|
||||
value.set(cached.get());
|
||||
return;
|
||||
}
|
||||
|
||||
match self.effective_key() {
|
||||
Some(effective_key) => key_type_to_jsval(cx, &effective_key, value),
|
||||
Some(effective_key) => key_type_to_jsval(cx, &effective_key, value.reborrow()),
|
||||
None => value.set(UndefinedValue()),
|
||||
}
|
||||
|
||||
*self.cached_primary_key.borrow_mut() = Some(Heap::default());
|
||||
self.cached_primary_key
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.set(value.get());
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/IndexedDB/#dom-idbcursor-request>
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
[idbcursor-key.any.sharedworker.html]
|
||||
expected: ERROR
|
||||
|
||||
[idbcursor-key.any.worker.html]
|
||||
[IDBCursor.key 2]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idbcursor-key.any.html]
|
||||
[IDBCursor.key 2]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idbcursor-key.any.serviceworker.html]
|
||||
expected: ERROR
|
||||
|
||||
Reference in New Issue
Block a user