Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 46 additions & 8 deletions crates/perry-runtime/src/web_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,33 @@ pub extern "C" fn storage_constructor_illegal(_closure: *const ClosureHeader) ->
throw_error("Illegal constructor")
}

extern "C" fn storage_global_getter(_closure: *const ClosureHeader) -> f64 {
f64::from_bits(TAG_UNDEFINED)
extern "C" fn local_storage_global_getter(_closure: *const ClosureHeader) -> f64 {
storage_global_value(StorageKind::Local)
}

extern "C" fn session_storage_global_getter(_closure: *const ClosureHeader) -> f64 {
storage_global_value(StorageKind::Session)
}

extern "C" fn storage_length_getter(_closure: *const ClosureHeader) -> f64 {
let Some(kind) = receiver_kind() else {
return throw_type_error("Illegal invocation");
};
with_store(kind, |store| store.len() as f64)
}

extern "C" fn storage_global_setter(_closure: *const ClosureHeader, _value: f64) -> f64 {
f64::from_bits(TAG_UNDEFINED)
}

fn storage_global_value(kind: StorageKind) -> f64 {
let obj = storage_object(kind);
if obj.is_null() {
return f64::from_bits(TAG_UNDEFINED);
}
crate::value::js_nanbox_pointer(obj as i64)
}

extern "C" fn storage_get_item(_closure: *const ClosureHeader, key: f64) -> f64 {
let Some(kind) = receiver_kind() else {
return throw_type_error("Illegal invocation");
Expand Down Expand Up @@ -210,8 +229,18 @@ pub(crate) fn install_storage_globals(
Ordering::Release,
);

set_global_storage_property(global, "localStorage", local);
set_global_storage_property(global, "sessionStorage", session);
set_global_storage_property(
global,
"localStorage",
local,
local_storage_global_getter as *const u8,
);
set_global_storage_property(
global,
"sessionStorage",
session,
session_storage_global_getter as *const u8,
);
}

fn install_method(proto: *mut ObjectHeader, name: &str, func_ptr: *const u8, arity: u32) {
Expand Down Expand Up @@ -245,11 +274,11 @@ fn install_method(proto: *mut ObjectHeader, name: &str, func_ptr: *const u8, ari
}

fn install_storage_length_accessor(proto: *mut ObjectHeader) {
let getter = crate::closure::js_closure_alloc(storage_global_getter as *const u8, 0);
let getter = crate::closure::js_closure_alloc(storage_length_getter as *const u8, 0);
if getter.is_null() {
return;
}
crate::closure::js_register_closure_arity(storage_global_getter as *const u8, 0);
crate::closure::js_register_closure_arity(storage_length_getter as *const u8, 0);
crate::object::set_bound_native_closure_name(getter, "get length");
crate::object::js_object_set_field_by_name(
proto,
Expand Down Expand Up @@ -313,7 +342,12 @@ fn make_storage_object(kind: StorageKind, proto: *mut ObjectHeader) -> *mut Obje
obj
}

fn set_global_storage_property(global: *mut ObjectHeader, name: &str, value: *mut ObjectHeader) {
fn set_global_storage_property(
global: *mut ObjectHeader,
name: &str,
value: *mut ObjectHeader,
getter_ptr: *const u8,
) {
crate::object::js_object_set_field_by_name(
global,
string(name),
Expand All @@ -325,9 +359,13 @@ fn set_global_storage_property(global: *mut ObjectHeader, name: &str, value: *mu
PropertyAttrs::new(true, true, true),
);

let getter = crate::closure::js_closure_alloc(storage_global_getter as *const u8, 0);
let getter = crate::closure::js_closure_alloc(getter_ptr, 0);
let setter = crate::closure::js_closure_alloc(storage_global_setter as *const u8, 0);
if !getter.is_null() && !setter.is_null() {
crate::closure::js_register_closure_arity(getter_ptr, 0);
crate::closure::js_register_closure_arity(storage_global_setter as *const u8, 1);
crate::object::set_bound_native_closure_name(getter, &format!("get {name}"));
crate::object::set_bound_native_closure_name(setter, &format!("set {name}"));
crate::object::set_builtin_accessor_descriptor(
global as usize,
name.to_string(),
Expand Down
13 changes: 13 additions & 0 deletions test-parity/node-suite/globals/storage-globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ globalDesc("Storage desc", "Storage");
globalDesc("localStorage desc", "localStorage");
globalDesc("sessionStorage desc", "sessionStorage");

const localStorageDesc: any = Object.getOwnPropertyDescriptor(globalThis, "localStorage");
const sessionStorageDesc: any = Object.getOwnPropertyDescriptor(globalThis, "sessionStorage");
const lengthDesc: any = Object.getOwnPropertyDescriptor(Storage.prototype, "length");
show(
"storage getter identity",
[
localStorageDesc.get.call(g) === localStorage,
sessionStorageDesc.get.call(g) === sessionStorage,
].join("/"),
);
show("length getter session", lengthDesc.get.call(sessionStorage));
showError("length getter proto", () => lengthDesc.get.call(Storage.prototype));

for (const name of ["clear", "getItem", "key", "removeItem", "setItem"]) {
const fn = (Storage.prototype as any)[name];
const desc: any = Object.getOwnPropertyDescriptor(Storage.prototype, name);
Expand Down