/
githubmirror
/
servo
Обзор
Документация
Войти
/
githubmirror
/
servo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
components/script/window_named_properties.rs
279 строк
8 KB
Tim van der Lippe
script: Remove SafeJSContext (#46151)
01 июл 2026, 18:53
Не верифицирован
01 июл 2026, 18:53
843b021
Код
Авторство
О чём код?
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::ptr; use std::ptr::NonNull; use std::sync::LazyLock; use js::conversions::jsstr_to_string; use js::glue::{AppendToIdVector, CreateProxyHandler, ProxyTraps}; use js::jsapi::{ Handle, HandleId, HandleObject, JSCLASS_DELAY_METADATA_BUILDER, JSCLASS_IS_PROXY, JSCLASS_RESERVED_SLOTS_MASK, JSCLASS_RESERVED_SLOTS_SHIFT, JSClass, JSClass_NON_NATIVE, JSContext, JSErrNum, JSPROP_READONLY, MutableHandle, MutableHandleIdVector, MutableHandleObject, ObjectOpResult, PropertyDescriptor, ProxyClassExtension, ProxyClassOps, ProxyObjectOps, SymbolCode, UndefinedHandleValue, }; use js::jsid::SymbolId; use js::jsval::UndefinedValue; use js::rust::wrappers2::{GetWellKnownSymbol, JS_SetImmutablePrototype, NewProxyObject}; use js::rust::{ Handle as RustHandle, HandleObject as RustHandleObject, MutableHandle as RustMutableHandle, MutableHandleObject as RustMutableHandleObject, }; use script_bindings::proxyhandler::set_property_descriptor; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::root::Root; use crate::dom::bindings::utils::has_property_on_prototype; use crate::dom::globalscope::GlobalScope; use crate::dom::window::Window; use crate::js::conversions::ToJSValConvertible; struct SyncWrapper(*const libc::c_void); #[expect(unsafe_code)] unsafe impl Sync for SyncWrapper {} #[expect(unsafe_code)] unsafe impl Send for SyncWrapper {} static HANDLER: LazyLock<SyncWrapper> = LazyLock::new(|| { let traps = ProxyTraps { enter: None, getOwnPropertyDescriptor: Some(get_own_property_descriptor), defineProperty: Some(define_property), ownPropertyKeys: Some(own_property_keys), delete_: Some(delete), enumerate: None, getPrototypeIfOrdinary: Some(get_prototype_if_ordinary), getPrototype: None, setPrototype: None, setImmutablePrototype: None, preventExtensions: Some(prevent_extensions), isExtensible: Some(is_extensible), has: None, get: None, set: None, call: None, construct: None, hasOwn: None, getOwnEnumerablePropertyKeys: None, nativeCall: None, objectClassIs: None, className: Some(class_name), fun_toString: None, boxedValue_unbox: None, defaultValue: None, trace: None, finalize: None, objectMoved: None, isCallable: None, isConstructor: None, }; #[expect(unsafe_code)] unsafe { SyncWrapper(CreateProxyHandler(&traps, ptr::null())) } }); #[expect(unsafe_code)] unsafe extern "C" fn get_own_property_descriptor( cx: *mut JSContext, proxy: HandleObject, id: HandleId, desc: MutableHandle<PropertyDescriptor>, is_none: *mut bool, ) -> bool { // SAFETY: it is safe to construct a JSContext from an engine callback. let mut cx = unsafe { js::context::JSContext::from_ptr(ptr::NonNull::new(cx).unwrap()) }; if id.is_symbol() { if id.get().asBits_ == SymbolId(unsafe { GetWellKnownSymbol(&cx, SymbolCode::toStringTag) }).asBits_ { rooted!(&in(cx) let mut rval = UndefinedValue()); "WindowProperties".safe_to_jsval(&mut cx, rval.handle_mut()); set_property_descriptor( unsafe { RustMutableHandle::from_raw(desc) }, rval.handle(), JSPROP_READONLY.into(), unsafe { &mut *is_none }, ); } return true; } let mut found = false; let lookup_succeeded = has_property_on_prototype( &mut cx, unsafe { RustHandle::from_raw(proxy) }, unsafe { RustHandle::from_raw(id) }, &mut found, ); if !lookup_succeeded { return false; } if found { return true; } let s = if id.is_string() { unsafe { jsstr_to_string(&cx, NonNull::new(id.to_string()).unwrap()) } } else if id.is_int() { // If the property key is an integer index, convert it to a String too. // For indexed access on the window object, which may shadow this, see // the getOwnPropertyDescriptor trap in dom/windowproxy.rs. id.to_int().to_string() } else if id.is_symbol() { // Symbol properties were already handled above. unreachable!() } else { unimplemented!() }; if s.is_empty() { return true; } let window = Root::downcast::<Window>(unsafe { GlobalScope::from_object(proxy.get()) }) .expect("global is not a window"); if let Some(obj) = window.NamedGetter(&mut cx, s.into()) { rooted!(&in(cx) let mut rval = UndefinedValue()); obj.safe_to_jsval(&mut cx, rval.handle_mut()); set_property_descriptor( unsafe { RustMutableHandle::from_raw(desc) }, rval.handle(), 0, unsafe { &mut *is_none }, ); } true } #[expect(unsafe_code)] unsafe extern "C" fn own_property_keys( cx: *mut JSContext, _proxy: HandleObject, props: MutableHandleIdVector, ) -> bool { // TODO is this all we need to return? compare with gecko: // https://searchfox.org/mozilla-central/rev/af78418c4b5f2c8721d1a06486cf4cf0b33e1e8d/dom/base/WindowNamedPropertiesHandler.cpp#175-232 // see also https://github.com/whatwg/html/issues/9068 unsafe { rooted!(in(cx) let mut rooted = SymbolId(js::jsapi::GetWellKnownSymbol(cx, SymbolCode::toStringTag))); AppendToIdVector(props, rooted.handle().into()); } true } #[expect(unsafe_code)] unsafe extern "C" fn define_property( _cx: *mut JSContext, _proxy: HandleObject, _id: HandleId, _desc: Handle<PropertyDescriptor>, result: *mut ObjectOpResult, ) -> bool { unsafe { (*result).code_ = JSErrNum::JSMSG_CANT_DEFINE_WINDOW_NAMED_PROPERTY as usize; } true } #[expect(unsafe_code)] unsafe extern "C" fn delete( _cx: *mut JSContext, _proxy: HandleObject, _id: HandleId, result: *mut ObjectOpResult, ) -> bool { unsafe { (*result).code_ = JSErrNum::JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY as usize; } true } #[expect(unsafe_code)] unsafe extern "C" fn get_prototype_if_ordinary( _cx: *mut JSContext, proxy: HandleObject, is_ordinary: *mut bool, proto: MutableHandleObject, ) -> bool { unsafe { *is_ordinary = true; proto.set(js::jsapi::GetStaticPrototype(proxy.get())); } true } #[expect(unsafe_code)] unsafe extern "C" fn prevent_extensions( _cx: *mut JSContext, _proxy: HandleObject, result: *mut ObjectOpResult, ) -> bool { unsafe { (*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as usize; } true } #[expect(unsafe_code)] unsafe extern "C" fn is_extensible( _cx: *mut JSContext, _proxy: HandleObject, extensible: *mut bool, ) -> bool { unsafe { *extensible = true; } true } #[expect(unsafe_code)] unsafe extern "C" fn class_name(_cx: *mut JSContext, _proxy: HandleObject) -> *const libc::c_char { c"WindowProperties".as_ptr() } // Maybe this should be a DOMJSClass. See https://bugzilla.mozilla.org/show_bug.cgi?id=787070 #[expect(unsafe_code)] static CLASS: JSClass = JSClass { name: c"WindowProperties".as_ptr(), flags: JSClass_NON_NATIVE | JSCLASS_IS_PROXY | JSCLASS_DELAY_METADATA_BUILDER | ((1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT), /* JSCLASS_HAS_RESERVED_SLOTS(1) */ cOps: unsafe { &ProxyClassOps }, spec: ptr::null(), ext: unsafe { &ProxyClassExtension }, oOps: unsafe { &ProxyObjectOps }, }; #[expect(unsafe_code)] pub(crate) fn create( cx: &mut js::context::JSContext, proto: RustHandleObject, mut properties_obj: RustMutableHandleObject, ) { unsafe { properties_obj.set(NewProxyObject( cx, HANDLER.0, RustHandle::from_raw(UndefinedHandleValue), proto.get(), &CLASS, false, )); } assert!(!properties_obj.get().is_null()); let mut succeeded = false; unsafe { assert!(JS_SetImmutablePrototype( cx, properties_obj.handle(), &mut succeeded )); } assert!(succeeded); }