Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazily define interface objects on globals (fixes #6419) #9652

Merged
merged 5 commits into from Feb 25, 2016
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Lazily define interface objects on globals (fixes #6419)

  • Loading branch information
nox committed Feb 25, 2016
commit 1559f5a39fab451d83ad40ef960d9a3e5cd9f453
@@ -79,6 +79,8 @@ libc = "0.2"
log = "0.3"
num = "0.1.24"
rand = "0.3"
phf = "0.7.13"
phf_macros = "0.7.13"
ref_slice = "0.1.0"
rustc-serialize = "0.3"
selectors = {version = "0.5", features = ["heap_size"]}
@@ -1779,10 +1779,10 @@ def define(self):
}
if self.descriptor.isGlobal():
assert not self.descriptor.weakReferenceable
args["enumerateHook"] = "Some(js::jsapi::JS_EnumerateStandardClasses)"
args["enumerateHook"] = "Some(enumerate_global)"
args["flags"] = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL"
args["slots"] = "JSCLASS_GLOBAL_SLOT_COUNT + 1"
args["resolveHook"] = "Some(js::jsapi::JS_ResolveStandardClass)"
args["resolveHook"] = "Some(resolve_global)"
args["traceHook"] = "js::jsapi::JS_GlobalObjectTraceHook"
elif self.descriptor.weakReferenceable:
args["slots"] = "2"
@@ -2280,11 +2280,8 @@ def definition_body(self):
%(copyUnforgeable)s
(*raw).init_reflector(obj.ptr);
let ret = Root::from_ref(&*raw);
RegisterBindings::Register(cx, obj.handle());
ret""" % {'copyUnforgeable': unforgeable, 'createObject': create})
Root::from_ref(&*raw)\
""" % {'copyUnforgeable': unforgeable, 'createObject': create})


class CGIDLInterface(CGThing):
@@ -5447,12 +5444,12 @@ def __init__(self, config, prefix, webIDLFile):
'dom::bindings::utils::{DOMClass, DOMJSClass}',
'dom::bindings::utils::{DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, JSCLASS_DOM_GLOBAL}',
'dom::bindings::utils::{ProtoOrIfaceArray, create_dom_global}',
'dom::bindings::utils::{finalize_global, find_enum_string_index, generic_getter}',
'dom::bindings::utils::{generic_lenient_getter, generic_lenient_setter}',
'dom::bindings::utils::{enumerate_global, finalize_global, find_enum_string_index}',
'dom::bindings::utils::{generic_getter, generic_lenient_getter, generic_lenient_setter}',
'dom::bindings::utils::{generic_method, generic_setter, get_array_index_from_id}',
'dom::bindings::utils::{get_dictionary_property, get_property_on_prototype}',
'dom::bindings::utils::{get_proto_or_iface_array, has_property_on_prototype}',
'dom::bindings::utils::{is_platform_object, set_dictionary_property}',
'dom::bindings::utils::{is_platform_object, resolve_global, set_dictionary_property}',
'dom::bindings::utils::{throwing_constructor, trace_global}',
'dom::bindings::trace::{JSTraceable, RootedTraceable}',
'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}',
@@ -6095,6 +6092,37 @@ class GlobalGenRoots():
call the appropriate define/declare method.
"""

@staticmethod
def InterfaceObjectMap(config):
mods = [
"dom::bindings::codegen",
"js::jsapi::{HandleObject, JSContext}",
"phf",
]
imports = CGList([CGGeneric("use %s;" % mod) for mod in mods], "\n")

pairs = []
for d in config.getDescriptors(hasInterfaceObject=True):
binding = toBindingNamespace(d.name)
pairs.append((d.name, binding))
for ctor in d.interface.namedConstructors:
pairs.append((ctor.identifier.name, binding))
pairs.sort(key=operator.itemgetter(0))
mappings = [
CGGeneric('b"%s" => codegen::Bindings::%s::DefineDOMInterface as fn(_, _),' % pair)
for pair in pairs
]
mapType = "phf::Map<&'static [u8], fn(*mut JSContext, HandleObject)>"
phf = CGWrapper(
CGIndenter(CGList(mappings, "\n")),
pre="pub static MAP: %s = phf_map! {\n" % mapType,
post="\n};\n")

return CGList([
CGGeneric(AUTOGENERATED_WARNING_COMMENT),
CGList([imports, phf], "\n\n")
])

@staticmethod
def PrototypeList(config):
# Prototype ID enum.
@@ -62,6 +62,7 @@ def main():
to_generate = [
('PrototypeList', 'PrototypeList.rs'),
('RegisterBindings', 'RegisterBindings.rs'),
('InterfaceObjectMap', 'InterfaceObjectMap.rs'),
('InterfaceTypes', 'InterfaceTypes.rs'),
('InheritTypes', 'InheritTypes.rs'),
('Bindings', os.path.join('Bindings', 'mod.rs')),
@@ -159,6 +159,9 @@ pub mod codegen {
pub mod Bindings {
include!(concat!(env!("OUT_DIR"), "/Bindings/mod.rs"));
}
pub mod InterfaceObjectMap {
include!(concat!(env!("OUT_DIR"), "/InterfaceObjectMap.rs"));
}
pub mod InterfaceTypes {
include!(concat!(env!("OUT_DIR"), "/InterfaceTypes.rs"));
}
@@ -4,6 +4,7 @@

//! Various utilities to glue JavaScript and the DOM implementation together.

use dom::bindings::codegen::InterfaceObjectMap;
use dom::bindings::codegen::PrototypeList;
use dom::bindings::codegen::PrototypeList::{MAX_PROTO_CHAIN_LENGTH, PROTO_OR_IFACE_LENGTH};
use dom::bindings::conversions::{DOM_OBJECT_SLOT, is_dom_class};
@@ -18,16 +19,18 @@ use js;
use js::error::throw_type_error;
use js::glue::{CallJitGetterOp, CallJitMethodOp, CallJitSetterOp, IsWrapper};
use js::glue::{GetCrossCompartmentWrapper, WrapperNew};
use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT};
use js::glue::{RUST_JSID_TO_INT, UnwrapObject};
use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT, RUST_JSID_IS_STRING};
use js::glue::{RUST_JSID_TO_INT, RUST_JSID_TO_STRING, UnwrapObject};
use js::jsapi::{CallArgs, CompartmentOptions, DOMCallbacks, GetGlobalForObjectCrossCompartment};
use js::jsapi::{HandleId, HandleObject, HandleValue, Heap, JSAutoCompartment, JSClass, JSContext};
use js::jsapi::{JSJitInfo, JSObject, JSTraceOp, JSTracer, JSVersion, JSWrapObjectCallbacks};
use js::jsapi::{JS_DeletePropertyById1, JS_FireOnNewGlobalObject, JS_ForwardGetPropertyTo};
use js::jsapi::{JS_GetClass, JS_GetProperty, JS_GetPrototype, JS_GetReservedSlot, JS_HasProperty};
use js::jsapi::{JS_HasPropertyById, JS_IsExceptionPending, JS_NewGlobalObject};
use js::jsapi::{JS_ObjectToOuterObject, JS_SetProperty, JS_SetReservedSlot};
use js::jsapi::{MutableHandleValue, ObjectOpResult, OnNewGlobalHookOption, RootedObject};
use js::jsapi::{JS_DeletePropertyById1, JS_EnumerateStandardClasses, JS_FireOnNewGlobalObject};
use js::jsapi::{JS_ForwardGetPropertyTo, JS_GetClass, JS_GetLatin1StringCharsAndLength};
use js::jsapi::{JS_GetProperty, JS_GetPrototype, JS_GetReservedSlot, JS_HasProperty};
use js::jsapi::{JS_HasPropertyById, JS_IsExceptionPending, JS_IsGlobalObject, JS_NewGlobalObject};
use js::jsapi::{JS_ObjectToOuterObject, JS_ResolveStandardClass, JS_SetProperty};
use js::jsapi::{JS_SetReservedSlot, JS_StringHasLatin1Chars, MutableHandleValue, ObjectOpResult};
use js::jsapi::{OnNewGlobalHookOption, RootedObject};
use js::jsval::{JSVal};
use js::jsval::{PrivateValue, UndefinedValue};
use js::rust::{GCMethods, ToString};
@@ -37,6 +40,7 @@ use std::default::Default;
use std::ffi::CString;
use std::os::raw::c_void;
use std::ptr;
use std::slice;
use util::non_geckolib::jsstring_to_str;

/// Proxy handler for a WindowProxy.
@@ -364,6 +368,56 @@ pub unsafe fn trace_global(tracer: *mut JSTracer, obj: *mut JSObject) {
}
}

/// Enumerate lazy properties of a global object.
pub unsafe extern "C" fn enumerate_global(cx: *mut JSContext, obj: HandleObject) -> bool {
assert!(JS_IsGlobalObject(obj.get()));
if !JS_EnumerateStandardClasses(cx, obj) {
return false;
}
for init_fun in InterfaceObjectMap::MAP.values() {
init_fun(cx, obj);
}
true
}

/// Resolve a lazy global property, for interface objects and named constructors.
pub unsafe extern "C" fn resolve_global(
cx: *mut JSContext,
obj: HandleObject,
id: HandleId,
rval: *mut bool)
-> bool {
assert!(JS_IsGlobalObject(obj.get()));
if !JS_ResolveStandardClass(cx, obj, id, rval) {
return false;
}
if *rval {
return true;
}
if !RUST_JSID_IS_STRING(id) {
*rval = false;
return true;
}

let string = RUST_JSID_TO_STRING(id);
if !JS_StringHasLatin1Chars(string) {
*rval = false;
return true;
}
let mut length = 0;
let ptr = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), string, &mut length);
assert!(!ptr.is_null());
let bytes = slice::from_raw_parts(ptr, length as usize);

if let Some(init_fun) = InterfaceObjectMap::MAP.get(bytes) {
init_fun(cx, obj);
*rval = true;
} else {
*rval = false;
}
true
}

unsafe extern "C" fn wrap(cx: *mut JSContext,
_existing: HandleObject,
obj: HandleObject)
@@ -26,6 +26,7 @@
#![doc = "The script crate contains all matters DOM."]

#![plugin(heapsize_plugin)]
#![plugin(phf_macros)]
#![plugin(plugins)]

extern crate angle;
@@ -55,6 +56,7 @@ extern crate msg;
extern crate net_traits;
extern crate num;
extern crate offscreen_gl_context;
extern crate phf;
#[macro_use]
extern crate profile_traits;
extern crate rand;

Some generated files are not rendered by default. Learn more.

Some generated files are not rendered by default. Learn more.

Some generated files are not rendered by default. Learn more.

},
"local_changes": {
"deleted": [],
"items": {},
"items": {
"testharness": {
"WebIDL/ecmascript-binding/interface-object.html": [
{
"path": "WebIDL/ecmascript-binding/interface-object.html",
"url": "/WebIDL/ecmascript-binding/interface-object.html"
}
]
}
},
"reftest_nodes": {}
},
"reftest_nodes": {
@@ -0,0 +1,28 @@
<!doctype html>
<meta charset="utf-8">
<title>Interface objects</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
test(function () {
assert_equals(typeof window.Blob, "function")
delete window.Blob;
assert_equals(window.Blob, undefined);
}, "An interface object deleted after it has been accessed is undefined");

test(function () {
delete window.File;
assert_equals(window.File, undefined);
}, "An interface object deleted before it has been defined is undefined");

test(function () {
delete window.ImageData;
assert_equals(Object.getOwnPropertyDescriptor(window, "ImageData"), undefined);
delete window.ImageData;
assert_equals(Object.getOwnPropertyDescriptor(window, "ImageData"), undefined);
}, "Interface objects deleted multiple times stay deleted");

test(function () {
assert_equals(window["abc\udc88"], undefined);
}, "Fancy property names don't break the resolve hook on Window");
</script>
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.