Remove Object.prototype.watch/unwatch.
This commit is contained in:
parent
a0f7a833d1
commit
5cfd8a746e
|
@ -120,6 +120,57 @@ S4EStatusService.prototype =
|
||||||
},
|
},
|
||||||
|
|
||||||
buildBinding: function() {
|
buildBinding: function() {
|
||||||
|
|
||||||
|
// Object.prototype.watch() shim, based on Eli Grey's polyfill
|
||||||
|
// object.watch
|
||||||
|
if (!this._window.XULBrowserWindow.watch) {
|
||||||
|
Object.defineProperty(this._window.XULBrowserWindow, "watch", {
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true,
|
||||||
|
writable: false,
|
||||||
|
value: function (prop, handler) {
|
||||||
|
var oldval = this[prop],
|
||||||
|
newval = oldval,
|
||||||
|
getter = function () {
|
||||||
|
return newval;
|
||||||
|
},
|
||||||
|
setter = function (val) {
|
||||||
|
oldval = newval;
|
||||||
|
return newval = handler.call(this, prop, oldval, val);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (delete this[prop]) { // can't watch constants
|
||||||
|
Object.defineProperty(this, prop, {
|
||||||
|
get: getter,
|
||||||
|
set: setter,
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
// This fails fatally on non-configurable props, so just
|
||||||
|
// ignore errors if it does.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// object.unwatch
|
||||||
|
if (!this._window.XULBrowserWindow.unwatch) {
|
||||||
|
Object.defineProperty(this._window.XULBrowserWindow, "unwatch", {
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true,
|
||||||
|
writable: false,
|
||||||
|
value: function (prop) {
|
||||||
|
var val = this[prop];
|
||||||
|
delete this[prop]; // remove accessors
|
||||||
|
this[prop] = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let XULBWPropHandler = function(prop, oldval, newval) {
|
let XULBWPropHandler = function(prop, oldval, newval) {
|
||||||
CU.reportError("Attempt to modify XULBrowserWindow." + prop);
|
CU.reportError("Attempt to modify XULBrowserWindow." + prop);
|
||||||
return oldval;
|
return oldval;
|
||||||
|
@ -139,21 +190,6 @@ S4EStatusService.prototype =
|
||||||
this._window.XULBrowserWindow[prop] = this[prop].bind(this);
|
this._window.XULBrowserWindow[prop] = this[prop].bind(this);
|
||||||
this._window.XULBrowserWindow.watch(prop, XULBWPropHandler);
|
this._window.XULBrowserWindow.watch(prop, XULBWPropHandler);
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
let XULBWHandler = function(prop, oldval, newval) {
|
|
||||||
if(!newval)
|
|
||||||
{
|
|
||||||
return newval;
|
|
||||||
}
|
|
||||||
CU.reportError("XULBrowserWindow changed. Updating S4E bindings.");
|
|
||||||
this._window.setTimeout(function(self)
|
|
||||||
{
|
|
||||||
self.buildBinding();
|
|
||||||
}, 0, this);
|
|
||||||
return newval;
|
|
||||||
};
|
|
||||||
|
|
||||||
this._window.watch("XULBrowserWindow", XULBWHandler);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function()
|
destroy: function()
|
||||||
|
|
|
@ -57,8 +57,8 @@ var consoleOpened = Task.async(function* (hud) {
|
||||||
// 4 values, and the following properties:
|
// 4 values, and the following properties:
|
||||||
// __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__
|
// __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__
|
||||||
// __proto__ hasOwnProperty isPrototypeOf propertyIsEnumerable
|
// __proto__ hasOwnProperty isPrototypeOf propertyIsEnumerable
|
||||||
// toLocaleString toString toSource unwatch valueOf watch constructor.
|
// toLocaleString toString toSource valueOfconstructor.
|
||||||
is(popup.itemCount, 19, "popup.itemCount is correct");
|
is(popup.itemCount, 17, "popup.itemCount is correct");
|
||||||
|
|
||||||
let sameItems = popup.getItems().reverse().map(function (e) {
|
let sameItems = popup.getItems().reverse().map(function (e) {
|
||||||
return e.label;
|
return e.label;
|
||||||
|
@ -82,36 +82,34 @@ var consoleOpened = Task.async(function* (hud) {
|
||||||
"toLocaleString",
|
"toLocaleString",
|
||||||
"toSource",
|
"toSource",
|
||||||
"toString",
|
"toString",
|
||||||
"unwatch",
|
|
||||||
"valueOf",
|
"valueOf",
|
||||||
"watch",
|
|
||||||
][index] === prop;
|
][index] === prop;
|
||||||
}), "getItems returns the items we expect");
|
}), "getItems returns the items we expect");
|
||||||
|
|
||||||
is(popup.selectedIndex, 18,
|
is(popup.selectedIndex, 16,
|
||||||
"Index of the first item from bottom is selected.");
|
"Index of the first item from bottom is selected.");
|
||||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||||
|
|
||||||
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
|
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
|
||||||
|
|
||||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||||
is(popup.selectedItem.label, "watch", "watch is selected");
|
|
||||||
is(completeNode.value, prefix + "watch",
|
|
||||||
"completeNode.value holds watch");
|
|
||||||
|
|
||||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
|
||||||
|
|
||||||
is(popup.selectedIndex, 1, "index 1 is selected");
|
|
||||||
is(popup.selectedItem.label, "valueOf", "valueOf is selected");
|
is(popup.selectedItem.label, "valueOf", "valueOf is selected");
|
||||||
is(completeNode.value, prefix + "valueOf",
|
is(completeNode.value, prefix + "valueOf",
|
||||||
"completeNode.value holds valueOf");
|
"completeNode.value holds valueOf");
|
||||||
|
|
||||||
|
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||||
|
|
||||||
|
is(popup.selectedIndex, 1, "index 1 is selected");
|
||||||
|
is(popup.selectedItem.label, "toString", "toString is selected");
|
||||||
|
is(completeNode.value, prefix + "toString",
|
||||||
|
"completeNode.value holds toString");
|
||||||
|
|
||||||
EventUtils.synthesizeKey("VK_UP", {});
|
EventUtils.synthesizeKey("VK_UP", {});
|
||||||
|
|
||||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||||
is(popup.selectedItem.label, "watch", "watch is selected");
|
is(popup.selectedItem.label, "valueOf", "valueOf is selected");
|
||||||
is(completeNode.value, prefix + "watch",
|
is(completeNode.value, prefix + "valueOf",
|
||||||
"completeNode.value holds watch");
|
"completeNode.value holds valueOf");
|
||||||
|
|
||||||
let currentSelectionIndex = popup.selectedIndex;
|
let currentSelectionIndex = popup.selectedIndex;
|
||||||
|
|
||||||
|
@ -127,7 +125,7 @@ var consoleOpened = Task.async(function* (hud) {
|
||||||
"Index is less after Page UP");
|
"Index is less after Page UP");
|
||||||
|
|
||||||
EventUtils.synthesizeKey("VK_END", {});
|
EventUtils.synthesizeKey("VK_END", {});
|
||||||
is(popup.selectedIndex, 18, "index is last after End");
|
is(popup.selectedIndex, 16, "index is last after End");
|
||||||
|
|
||||||
EventUtils.synthesizeKey("VK_HOME", {});
|
EventUtils.synthesizeKey("VK_HOME", {});
|
||||||
is(popup.selectedIndex, 0, "index is first after Home");
|
is(popup.selectedIndex, 0, "index is first after Home");
|
||||||
|
@ -151,7 +149,7 @@ function popupHideAfterTab() {
|
||||||
// At this point the completion suggestion should be accepted.
|
// At this point the completion suggestion should be accepted.
|
||||||
ok(!popup.isOpen, "popup is not open");
|
ok(!popup.isOpen, "popup is not open");
|
||||||
|
|
||||||
is(jsterm.getInputValue(), "window.foobarBug585991.watch",
|
is(jsterm.getInputValue(), "window.foobarBug585991.valueOf",
|
||||||
"completion was successful after VK_TAB");
|
"completion was successful after VK_TAB");
|
||||||
|
|
||||||
ok(!completeNode.value, "completeNode is empty");
|
ok(!completeNode.value, "completeNode is empty");
|
||||||
|
@ -159,17 +157,17 @@ function popupHideAfterTab() {
|
||||||
popup.once("popup-opened", function onShown() {
|
popup.once("popup-opened", function onShown() {
|
||||||
ok(popup.isOpen, "popup is open");
|
ok(popup.isOpen, "popup is open");
|
||||||
|
|
||||||
is(popup.itemCount, 19, "popup.itemCount is correct");
|
is(popup.itemCount, 17, "popup.itemCount is correct");
|
||||||
|
|
||||||
is(popup.selectedIndex, 18, "First index from bottom is selected");
|
is(popup.selectedIndex, 16, "First index from bottom is selected");
|
||||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||||
|
|
||||||
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
|
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
|
||||||
|
|
||||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||||
is(popup.selectedItem.label, "watch", "watch is selected");
|
is(popup.selectedItem.label, "valueOf", "valueOf is selected");
|
||||||
is(completeNode.value, prefix + "watch",
|
is(completeNode.value, prefix + "valueOf",
|
||||||
"completeNode.value holds watch");
|
"completeNode.value holds valueOf");
|
||||||
|
|
||||||
popup.once("popup-closed", function onHidden() {
|
popup.once("popup-closed", function onHidden() {
|
||||||
ok(!popup.isOpen, "popup is not open after VK_ESCAPE");
|
ok(!popup.isOpen, "popup is not open after VK_ESCAPE");
|
||||||
|
@ -203,29 +201,29 @@ function testReturnKey() {
|
||||||
popup.once("popup-opened", function onShown() {
|
popup.once("popup-opened", function onShown() {
|
||||||
ok(popup.isOpen, "popup is open");
|
ok(popup.isOpen, "popup is open");
|
||||||
|
|
||||||
is(popup.itemCount, 19, "popup.itemCount is correct");
|
is(popup.itemCount, 17, "popup.itemCount is correct");
|
||||||
|
|
||||||
is(popup.selectedIndex, 18, "First index from bottom is selected");
|
is(popup.selectedIndex, 16, "First index from bottom is selected");
|
||||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||||
|
|
||||||
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
|
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
|
||||||
|
|
||||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||||
is(popup.selectedItem.label, "watch", "watch is selected");
|
is(popup.selectedItem.label, "valueOf", "valueOf is selected");
|
||||||
is(completeNode.value, prefix + "watch",
|
is(completeNode.value, prefix + "valueOf",
|
||||||
"completeNode.value holds watch");
|
"completeNode.value holds valueOf");
|
||||||
|
|
||||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||||
|
|
||||||
is(popup.selectedIndex, 1, "index 1 is selected");
|
is(popup.selectedIndex, 1, "index 1 is selected");
|
||||||
is(popup.selectedItem.label, "valueOf", "valueOf is selected");
|
is(popup.selectedItem.label, "toString", "toString is selected");
|
||||||
is(completeNode.value, prefix + "valueOf",
|
is(completeNode.value, prefix + "toString",
|
||||||
"completeNode.value holds valueOf");
|
"completeNode.value holds toString");
|
||||||
|
|
||||||
popup.once("popup-closed", function onHidden() {
|
popup.once("popup-closed", function onHidden() {
|
||||||
ok(!popup.isOpen, "popup is not open after VK_RETURN");
|
ok(!popup.isOpen, "popup is not open after VK_RETURN");
|
||||||
|
|
||||||
is(jsterm.getInputValue(), "window.foobarBug585991.valueOf",
|
is(jsterm.getInputValue(), "window.foobarBug585991.toString",
|
||||||
"completion was successful after VK_RETURN");
|
"completion was successful after VK_RETURN");
|
||||||
|
|
||||||
ok(!completeNode.value, "completeNode is empty");
|
ok(!completeNode.value, "completeNode is empty");
|
||||||
|
|
|
@ -1026,11 +1026,6 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool watch(JSContext *cx, JS::Handle<JSObject*> proxy,
|
|
||||||
JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const override;
|
|
||||||
virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
|
|
||||||
JS::Handle<jsid> id) const override;
|
|
||||||
|
|
||||||
static void ObjectMoved(JSObject *obj, const JSObject *old);
|
static void ObjectMoved(JSObject *obj, const JSObject *old);
|
||||||
|
|
||||||
static const nsOuterWindowProxy singleton;
|
static const nsOuterWindowProxy singleton;
|
||||||
|
@ -1398,20 +1393,6 @@ nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
nsOuterWindowProxy::watch(JSContext *cx, JS::Handle<JSObject*> proxy,
|
|
||||||
JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const
|
|
||||||
{
|
|
||||||
return js::WatchGuts(cx, proxy, id, callable);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
|
|
||||||
JS::Handle<jsid> id) const
|
|
||||||
{
|
|
||||||
return js::UnwatchGuts(cx, proxy, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsOuterWindowProxy::ObjectMoved(JSObject *obj, const JSObject *old)
|
nsOuterWindowProxy::ObjectMoved(JSObject *obj, const JSObject *old)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1968,8 +1968,6 @@ const js::ObjectOps sInterfaceObjectClassObjectOps = {
|
||||||
nullptr, /* setProperty */
|
nullptr, /* setProperty */
|
||||||
nullptr, /* getOwnPropertyDescriptor */
|
nullptr, /* getOwnPropertyDescriptor */
|
||||||
nullptr, /* deleteProperty */
|
nullptr, /* deleteProperty */
|
||||||
nullptr, /* watch */
|
|
||||||
nullptr, /* unwatch */
|
|
||||||
nullptr, /* getElements */
|
nullptr, /* getElements */
|
||||||
nullptr, /* enumerate */
|
nullptr, /* enumerate */
|
||||||
InterfaceObjectToString, /* funToString */
|
InterfaceObjectToString, /* funToString */
|
||||||
|
|
|
@ -13169,9 +13169,9 @@ class CGDictionary(CGThing):
|
||||||
# continues to match the list in test_Object.prototype_props.html
|
# continues to match the list in test_Object.prototype_props.html
|
||||||
if (member.identifier.name in
|
if (member.identifier.name in
|
||||||
["constructor", "toSource", "toString", "toLocaleString", "valueOf",
|
["constructor", "toSource", "toString", "toLocaleString", "valueOf",
|
||||||
"watch", "unwatch", "hasOwnProperty", "isPrototypeOf",
|
"hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
|
||||||
"propertyIsEnumerable", "__defineGetter__", "__defineSetter__",
|
"__defineGetter__", "__defineSetter__", "__lookupGetter__",
|
||||||
"__lookupGetter__", "__lookupSetter__", "__proto__"]):
|
"__lookupSetter__", "__proto__"]):
|
||||||
raise TypeError("'%s' member of %s dictionary shadows "
|
raise TypeError("'%s' member of %s dictionary shadows "
|
||||||
"a property of Object.prototype, and Xrays to "
|
"a property of Object.prototype, and Xrays to "
|
||||||
"Object can't handle that.\n"
|
"Object can't handle that.\n"
|
||||||
|
|
|
@ -274,19 +274,6 @@ DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||||
return result.succeed();
|
return result.succeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
BaseDOMProxyHandler::watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
|
||||||
JS::Handle<JSObject*> callable) const
|
|
||||||
{
|
|
||||||
return js::WatchGuts(cx, proxy, id, callable);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
BaseDOMProxyHandler::unwatch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const
|
|
||||||
{
|
|
||||||
return js::UnwatchGuts(cx, proxy, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx,
|
BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx,
|
||||||
JS::Handle<JSObject*> proxy,
|
JS::Handle<JSObject*> proxy,
|
||||||
|
|
|
@ -72,11 +72,6 @@ public:
|
||||||
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
|
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||||
JS::AutoIdVector &props) const override;
|
JS::AutoIdVector &props) const override;
|
||||||
|
|
||||||
bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
|
||||||
JS::Handle<JSObject*> callable) const override;
|
|
||||||
bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy,
|
|
||||||
JS::Handle<jsid> id) const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Hook for subclasses to implement shared ownPropertyKeys()/keys()
|
// Hook for subclasses to implement shared ownPropertyKeys()/keys()
|
||||||
// functionality. The "flags" argument is either JSITER_OWNONLY (for keys())
|
// functionality. The "flags" argument is either JSITER_OWNONLY (for keys())
|
||||||
|
|
|
@ -11,9 +11,9 @@ test(function() {
|
||||||
// Codegen.py's CGDictionary.getMemberDefinition method.
|
// Codegen.py's CGDictionary.getMemberDefinition method.
|
||||||
var expected = [
|
var expected = [
|
||||||
"constructor", "toSource", "toString", "toLocaleString", "valueOf",
|
"constructor", "toSource", "toString", "toLocaleString", "valueOf",
|
||||||
"watch", "unwatch", "hasOwnProperty", "isPrototypeOf",
|
"hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
|
||||||
"propertyIsEnumerable", "__defineGetter__", "__defineSetter__",
|
"__defineGetter__", "__defineSetter__", "__lookupGetter__",
|
||||||
"__lookupGetter__", "__lookupSetter__", "__proto__"
|
"__lookupSetter__", "__proto__"
|
||||||
];
|
];
|
||||||
assert_array_equals(props.sort(), expected.sort());
|
assert_array_equals(props.sort(), expected.sort());
|
||||||
}, "Own properties of Object.prototype");
|
}, "Own properties of Object.prototype");
|
||||||
|
|
|
@ -553,7 +553,6 @@ skip-if = true # Disabled for timeouts.
|
||||||
[test_viewport.html]
|
[test_viewport.html]
|
||||||
[test_documentAll.html]
|
[test_documentAll.html]
|
||||||
[test_document-element-inserted.html]
|
[test_document-element-inserted.html]
|
||||||
[test_document.watch.html]
|
|
||||||
[test_bug445004.html]
|
[test_bug445004.html]
|
||||||
skip-if = true || toolkit == 'android' # Disabled permanently (bug 559932).
|
skip-if = true || toolkit == 'android' # Disabled permanently (bug 559932).
|
||||||
[test_bug446483.html]
|
[test_bug446483.html]
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<!--
|
|
||||||
https://bugzilla.mozilla.org/show_bug.cgi?id=903332
|
|
||||||
-->
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Test for Bug 903332</title>
|
|
||||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
|
||||||
<script type="application/javascript">
|
|
||||||
|
|
||||||
/** Test for Bug 903332 **/
|
|
||||||
|
|
||||||
var watch1Called;
|
|
||||||
function watch1(prop, oldValue, newValue)
|
|
||||||
{
|
|
||||||
is(watch1Called, false, "watch1Called not reset properly?");
|
|
||||||
watch1Called = true;
|
|
||||||
|
|
||||||
is(prop, "cookie", "wrong property name passed to watch1");
|
|
||||||
return newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var watch2Called;
|
|
||||||
function watch2(prop, oldValue, newValue)
|
|
||||||
{
|
|
||||||
is(watch2Called, false, "watch2Called not reset properly?");
|
|
||||||
watch2Called = true;
|
|
||||||
|
|
||||||
is(prop, "cookie", "wrong property name passed to watch2");
|
|
||||||
return newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just in case subsequent tests depend on a particular value...
|
|
||||||
var originalValue = document.cookie;
|
|
||||||
ok(true, "originalValue: " + originalValue);
|
|
||||||
|
|
||||||
var originalPrefix = originalValue.length > 0 ? originalValue + "; " : "";
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// trial set (no watch) to verify things work
|
|
||||||
document.cookie = "first=set";
|
|
||||||
is(document.cookie, originalPrefix + "first=set",
|
|
||||||
"first value correct");
|
|
||||||
|
|
||||||
// add a watch
|
|
||||||
document.watch("cookie", watch1);
|
|
||||||
|
|
||||||
// set, check for watch invoked
|
|
||||||
watch1Called = false;
|
|
||||||
document.cookie = "second=set";
|
|
||||||
is(watch1Called, true, "watch1 function should be called");
|
|
||||||
is(document.cookie, originalPrefix + "first=set; second=set",
|
|
||||||
"second value correct");
|
|
||||||
|
|
||||||
// and a second time, just in case
|
|
||||||
watch1Called = false;
|
|
||||||
document.cookie = "third=set";
|
|
||||||
is(watch1Called, true, "watch1 function should be called");
|
|
||||||
is(document.cookie, originalPrefix + "first=set; second=set; third=set",
|
|
||||||
"third value correct");
|
|
||||||
|
|
||||||
// overwrite the current watch with a new one
|
|
||||||
document.watch("cookie", watch2);
|
|
||||||
|
|
||||||
// set, check for watch invoked
|
|
||||||
watch1Called = false;
|
|
||||||
watch2Called = false;
|
|
||||||
document.cookie = "fourth=set";
|
|
||||||
is(watch1Called, false, "watch1 invoked erroneously");
|
|
||||||
is(watch2Called, true, "watch2 function should be called");
|
|
||||||
is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set",
|
|
||||||
"fourth value correct");
|
|
||||||
|
|
||||||
// and a second time, just in case
|
|
||||||
watch1Called = false;
|
|
||||||
watch2Called = false;
|
|
||||||
document.cookie = "fifth=set";
|
|
||||||
is(watch1Called, false, "watch1 invoked erroneously");
|
|
||||||
is(watch2Called, true, "watch2 function should be called");
|
|
||||||
is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set; fifth=set",
|
|
||||||
"fifth value correct");
|
|
||||||
|
|
||||||
// remove the watch
|
|
||||||
document.unwatch("cookie");
|
|
||||||
|
|
||||||
// check for non-invocation now
|
|
||||||
watch1Called = false;
|
|
||||||
watch2Called = false;
|
|
||||||
document.cookie = "sixth=set";
|
|
||||||
is(watch1Called, false, "watch1 shouldn't be called");
|
|
||||||
is(watch2Called, false, "watch2 shouldn't be called");
|
|
||||||
is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set; fifth=set; sixth=set",
|
|
||||||
"sixth value correct");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// reset
|
|
||||||
document.unwatch("cookie"); // harmless, should be no-op except if bugs
|
|
||||||
|
|
||||||
var d = new Date();
|
|
||||||
d.setTime(0);
|
|
||||||
var suffix = "=; expires=" + d.toGMTString();
|
|
||||||
|
|
||||||
document.cookie = "first" + suffix;
|
|
||||||
document.cookie = "second" + suffix;
|
|
||||||
document.cookie = "third" + suffix;
|
|
||||||
document.cookie = "fourth" + suffix;
|
|
||||||
document.cookie = "fifth" + suffix;
|
|
||||||
document.cookie = "sixth" + suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
is(document.cookie, originalValue,
|
|
||||||
"document.cookie isn't what it was initially! expect bustage further " +
|
|
||||||
"down the line");
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=903332">Mozilla Bug 903332</a>
|
|
||||||
<p id="display"></p>
|
|
||||||
<div id="content" style="display: none">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<pre id="test">
|
|
||||||
</pre>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -248,7 +248,6 @@ const static js::ObjectOps sNPObjectJSWrapperObjectOps = {
|
||||||
nullptr, // setProperty
|
nullptr, // setProperty
|
||||||
nullptr, // getOwnPropertyDescriptor
|
nullptr, // getOwnPropertyDescriptor
|
||||||
nullptr, // deleteProperty
|
nullptr, // deleteProperty
|
||||||
nullptr, nullptr, // watch/unwatch
|
|
||||||
nullptr, // getElements
|
nullptr, // getElements
|
||||||
NPObjWrapper_Enumerate,
|
NPObjWrapper_Enumerate,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<script>//<![CDATA[
|
|
||||||
|
|
||||||
function add_watch()
|
|
||||||
{
|
|
||||||
document.getElementById("p").transform.baseVal.watch("0", function(){});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("load", add_watch, false);
|
|
||||||
|
|
||||||
//]]></script>
|
|
||||||
|
|
||||||
<path id="p" transform="scale(1)" />
|
|
||||||
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 297 B |
|
@ -1,15 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<script>//<![CDATA[
|
|
||||||
|
|
||||||
function add_watch()
|
|
||||||
{
|
|
||||||
document.getElementById("e").x.baseVal.watch("0", function(){});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("load", add_watch, false);
|
|
||||||
|
|
||||||
//]]></script>
|
|
||||||
|
|
||||||
<text id="e" x="10">foo</text>
|
|
||||||
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 283 B |
|
@ -1,15 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<script>//<![CDATA[
|
|
||||||
|
|
||||||
function add_watch()
|
|
||||||
{
|
|
||||||
document.getElementById("e").rotate.baseVal.watch("0", function(){});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("load", add_watch, false);
|
|
||||||
|
|
||||||
//]]></script>
|
|
||||||
|
|
||||||
<text id="e" rotate="10">foo</text>
|
|
||||||
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 293 B |
|
@ -1,15 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<script>//<![CDATA[
|
|
||||||
|
|
||||||
function add_watch()
|
|
||||||
{
|
|
||||||
document.getElementById("e").pathSegList.watch("0", function(){});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("load", add_watch, false);
|
|
||||||
|
|
||||||
//]]></script>
|
|
||||||
|
|
||||||
<path id="e" d="M0,0"/>
|
|
||||||
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 278 B |
|
@ -1,15 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<script>//<![CDATA[
|
|
||||||
|
|
||||||
function add_watch()
|
|
||||||
{
|
|
||||||
document.getElementById("e").points.watch("0", function(){});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("load", add_watch, false);
|
|
||||||
|
|
||||||
//]]></script>
|
|
||||||
|
|
||||||
<polygon id="e" points="0,0"/>
|
|
||||||
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 280 B |
|
@ -66,11 +66,6 @@ load 837450-1.svg
|
||||||
load 842463-1.html
|
load 842463-1.html
|
||||||
load 847138-1.svg
|
load 847138-1.svg
|
||||||
load 864509.svg
|
load 864509.svg
|
||||||
load 880544-1.svg
|
|
||||||
load 880544-2.svg
|
|
||||||
load 880544-3.svg
|
|
||||||
load 880544-4.svg
|
|
||||||
load 880544-5.svg
|
|
||||||
load 898915-1.svg
|
load 898915-1.svg
|
||||||
load 1035248-1.svg
|
load 1035248-1.svg
|
||||||
load 1035248-2.svg
|
load 1035248-2.svg
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Iframe test for bug 38959</title>
|
|
||||||
</head>
|
|
||||||
<body">
|
|
||||||
<script>
|
|
||||||
|
|
||||||
x = false;
|
|
||||||
window.opener.postMessage(1, "http://mochi.test:8888");
|
|
||||||
window.close();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Iframe test for bug 38959</title>
|
|
||||||
</head>
|
|
||||||
<body">
|
|
||||||
<script>
|
|
||||||
|
|
||||||
x = true;
|
|
||||||
window.opener.postMessage(2, "http://mochi.test:8888");
|
|
||||||
window.close();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -23,8 +23,6 @@ support-files =
|
||||||
grandchild_bug260264.html
|
grandchild_bug260264.html
|
||||||
iframe_bug304459-1.html
|
iframe_bug304459-1.html
|
||||||
iframe_bug304459-2.html
|
iframe_bug304459-2.html
|
||||||
iframe_bug38959-1.html
|
|
||||||
iframe_bug38959-2.html
|
|
||||||
iframe_bug430276-2.html
|
iframe_bug430276-2.html
|
||||||
iframe_bug430276.html
|
iframe_bug430276.html
|
||||||
iframe_bug440572.html
|
iframe_bug440572.html
|
||||||
|
@ -64,7 +62,6 @@ skip-if = toolkit == 'android' #TIMED_OUT
|
||||||
[test_bug377539.html]
|
[test_bug377539.html]
|
||||||
[test_bug384122.html]
|
[test_bug384122.html]
|
||||||
[test_bug389366.html]
|
[test_bug389366.html]
|
||||||
[test_bug38959.html]
|
|
||||||
[test_bug393974.html]
|
[test_bug393974.html]
|
||||||
[test_bug394769.html]
|
[test_bug394769.html]
|
||||||
[test_bug396843.html]
|
[test_bug396843.html]
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html>
|
|
||||||
<!--
|
|
||||||
https://bugzilla.mozilla.org/show_bug.cgi?id=38959
|
|
||||||
-->
|
|
||||||
<head>
|
|
||||||
<title>Test for Bug 38959</title>
|
|
||||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=38959">Mozilla Bug 38959</a>
|
|
||||||
<p id="display"></p>
|
|
||||||
<div id="content" style="display: none">
|
|
||||||
<iframe id="frame"></iframe>
|
|
||||||
</div>
|
|
||||||
<pre id="test">
|
|
||||||
<script type="application/javascript">
|
|
||||||
|
|
||||||
/** Test for Bug 38959 **/
|
|
||||||
|
|
||||||
var newValue;
|
|
||||||
|
|
||||||
function watcher(id, ol, ne)
|
|
||||||
{
|
|
||||||
newValue = ne;
|
|
||||||
return ne;
|
|
||||||
}
|
|
||||||
|
|
||||||
function openWindow(url, crossOrigin)
|
|
||||||
{
|
|
||||||
newValue = true;
|
|
||||||
var w = window.open(url);
|
|
||||||
w.watch("x", watcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
function receiveMessage(evt)
|
|
||||||
{
|
|
||||||
ok(newValue, "Watchpoints only allowed same-origin.");
|
|
||||||
if (evt.data == 1) {
|
|
||||||
openWindow("/tests/dom/tests/mochitest/bugs/iframe_bug38959-2.html");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SimpleTest.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
|
|
||||||
window.addEventListener("message", receiveMessage, false);
|
|
||||||
|
|
||||||
openWindow("http://example.org/tests/dom/tests/mochitest/bugs/iframe_bug38959-1.html");
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</pre>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -425,12 +425,6 @@ typedef bool
|
||||||
(* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
(* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||||
JS::ObjectOpResult& result);
|
JS::ObjectOpResult& result);
|
||||||
|
|
||||||
typedef bool
|
|
||||||
(* WatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
|
|
||||||
|
|
||||||
typedef bool
|
|
||||||
(* UnwatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id);
|
|
||||||
|
|
||||||
class JS_FRIEND_API(ElementAdder)
|
class JS_FRIEND_API(ElementAdder)
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -670,8 +664,6 @@ struct ObjectOps
|
||||||
SetPropertyOp setProperty;
|
SetPropertyOp setProperty;
|
||||||
GetOwnPropertyOp getOwnPropertyDescriptor;
|
GetOwnPropertyOp getOwnPropertyDescriptor;
|
||||||
DeletePropertyOp deleteProperty;
|
DeletePropertyOp deleteProperty;
|
||||||
WatchOp watch;
|
|
||||||
UnwatchOp unwatch;
|
|
||||||
GetElementsOp getElements;
|
GetElementsOp getElements;
|
||||||
JSNewEnumerateOp enumerate;
|
JSNewEnumerateOp enumerate;
|
||||||
JSFunToStringOp funToString;
|
JSFunToStringOp funToString;
|
||||||
|
@ -822,8 +814,8 @@ struct Class
|
||||||
* Objects of this class aren't native objects. They don't have Shapes that
|
* Objects of this class aren't native objects. They don't have Shapes that
|
||||||
* describe their properties and layout. Classes using this flag must
|
* describe their properties and layout. Classes using this flag must
|
||||||
* provide their own property behavior, either by being proxy classes (do
|
* provide their own property behavior, either by being proxy classes (do
|
||||||
* this) or by overriding all the ObjectOps except getElements, watch and
|
* this) or by overriding all the ObjectOps except getElements
|
||||||
* unwatch (don't do this).
|
* (don't do this).
|
||||||
*/
|
*/
|
||||||
static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
|
static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
|
||||||
|
|
||||||
|
@ -900,8 +892,6 @@ struct Class
|
||||||
const { return oOps ? oOps->getOwnPropertyDescriptor
|
const { return oOps ? oOps->getOwnPropertyDescriptor
|
||||||
: nullptr; }
|
: nullptr; }
|
||||||
DeletePropertyOp getOpsDeleteProperty() const { return oOps ? oOps->deleteProperty : nullptr; }
|
DeletePropertyOp getOpsDeleteProperty() const { return oOps ? oOps->deleteProperty : nullptr; }
|
||||||
WatchOp getOpsWatch() const { return oOps ? oOps->watch : nullptr; }
|
|
||||||
UnwatchOp getOpsUnwatch() const { return oOps ? oOps->unwatch : nullptr; }
|
|
||||||
GetElementsOp getOpsGetElements() const { return oOps ? oOps->getElements : nullptr; }
|
GetElementsOp getOpsGetElements() const { return oOps ? oOps->getElements : nullptr; }
|
||||||
JSNewEnumerateOp getOpsEnumerate() const { return oOps ? oOps->enumerate : nullptr; }
|
JSNewEnumerateOp getOpsEnumerate() const { return oOps ? oOps->enumerate : nullptr; }
|
||||||
JSFunToStringOp getOpsFunToString() const { return oOps ? oOps->funToString : nullptr; }
|
JSFunToStringOp getOpsFunToString() const { return oOps ? oOps->funToString : nullptr; }
|
||||||
|
|
|
@ -341,12 +341,6 @@ class JS_FRIEND_API(BaseProxyHandler)
|
||||||
virtual bool isCallable(JSObject* obj) const;
|
virtual bool isCallable(JSObject* obj) const;
|
||||||
virtual bool isConstructor(JSObject* obj) const;
|
virtual bool isConstructor(JSObject* obj) const;
|
||||||
|
|
||||||
// These two hooks must be overridden, or not overridden, in tandem -- no
|
|
||||||
// overriding just one!
|
|
||||||
virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
|
|
||||||
JS::HandleObject callable) const;
|
|
||||||
virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const;
|
|
||||||
|
|
||||||
virtual bool getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
|
virtual bool getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
|
||||||
ElementAdder* adder) const;
|
ElementAdder* adder) const;
|
||||||
|
|
||||||
|
|
|
@ -568,97 +568,6 @@ obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if JS_HAS_OBJ_WATCHPOINT
|
|
||||||
|
|
||||||
bool
|
|
||||||
js::WatchHandler(JSContext* cx, JSObject* obj_, jsid id_, const JS::Value& old,
|
|
||||||
JS::Value* nvp, void* closure)
|
|
||||||
{
|
|
||||||
RootedObject obj(cx, obj_);
|
|
||||||
RootedId id(cx, id_);
|
|
||||||
|
|
||||||
/* Avoid recursion on (obj, id) already being watched on cx. */
|
|
||||||
AutoResolving resolving(cx, obj, id, AutoResolving::WATCH);
|
|
||||||
if (resolving.alreadyStarted())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
FixedInvokeArgs<3> args(cx);
|
|
||||||
|
|
||||||
args[0].set(IdToValue(id));
|
|
||||||
args[1].set(old);
|
|
||||||
args[2].set(*nvp);
|
|
||||||
|
|
||||||
RootedValue callable(cx, ObjectValue(*static_cast<JSObject*>(closure)));
|
|
||||||
RootedValue thisv(cx, ObjectValue(*obj));
|
|
||||||
RootedValue rv(cx);
|
|
||||||
if (!Call(cx, callable, thisv, args, &rv))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*nvp = rv;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
obj_watch(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
|
|
||||||
RootedObject obj(cx, ToObject(cx, args.thisv()));
|
|
||||||
if (!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!GlobalObject::warnOnceAboutWatch(cx, obj))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (args.length() <= 1) {
|
|
||||||
ReportMissingArg(cx, args.calleev(), 1);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RootedObject callable(cx, ValueToCallable(cx, args[1], args.length() - 2));
|
|
||||||
if (!callable)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
RootedId propid(cx);
|
|
||||||
if (!ValueToId<CanGC>(cx, args[0], &propid))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!WatchProperty(cx, obj, propid, callable))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
args.rval().setUndefined();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
obj_unwatch(JSContext* cx, unsigned argc, Value* vp)
|
|
||||||
{
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
|
|
||||||
RootedObject obj(cx, ToObject(cx, args.thisv()));
|
|
||||||
if (!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!GlobalObject::warnOnceAboutWatch(cx, obj))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
RootedId id(cx);
|
|
||||||
if (args.length() != 0) {
|
|
||||||
if (!ValueToId<CanGC>(cx, args[0], &id))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
id = JSID_VOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UnwatchProperty(cx, obj, id))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
args.rval().setUndefined();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* JS_HAS_OBJ_WATCHPOINT */
|
|
||||||
|
|
||||||
/* ECMA 15.2.4.5. */
|
/* ECMA 15.2.4.5. */
|
||||||
bool
|
bool
|
||||||
js::obj_hasOwnProperty(JSContext* cx, unsigned argc, Value* vp)
|
js::obj_hasOwnProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
@ -1290,10 +1199,6 @@ static const JSFunctionSpec object_methods[] = {
|
||||||
JS_FN(js_toString_str, obj_toString, 0,0),
|
JS_FN(js_toString_str, obj_toString, 0,0),
|
||||||
JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0),
|
JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0),
|
||||||
JS_SELF_HOSTED_FN(js_valueOf_str, "Object_valueOf", 0,0),
|
JS_SELF_HOSTED_FN(js_valueOf_str, "Object_valueOf", 0,0),
|
||||||
#if JS_HAS_OBJ_WATCHPOINT
|
|
||||||
JS_FN(js_watch_str, obj_watch, 2,0),
|
|
||||||
JS_FN(js_unwatch_str, obj_unwatch, 1,0),
|
|
||||||
#endif
|
|
||||||
JS_FN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0),
|
JS_FN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0),
|
||||||
JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0),
|
JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0),
|
||||||
JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0),
|
JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0),
|
||||||
|
|
|
@ -2215,7 +2215,6 @@ const ObjectOps TypedObject::objectOps_ = {
|
||||||
TypedObject::obj_setProperty,
|
TypedObject::obj_setProperty,
|
||||||
TypedObject::obj_getOwnPropertyDescriptor,
|
TypedObject::obj_getOwnPropertyDescriptor,
|
||||||
TypedObject::obj_deleteProperty,
|
TypedObject::obj_deleteProperty,
|
||||||
nullptr, nullptr, /* watch/unwatch */
|
|
||||||
nullptr, /* getElements */
|
nullptr, /* getElements */
|
||||||
TypedObject::obj_enumerate,
|
TypedObject::obj_enumerate,
|
||||||
nullptr, /* thisValue */
|
nullptr, /* thisValue */
|
||||||
|
|
|
@ -2846,10 +2846,9 @@ struct UnmarkGrayTracer : public JS::CallbackTracer
|
||||||
*
|
*
|
||||||
* There is an additional complication for certain kinds of edges that are not
|
* There is an additional complication for certain kinds of edges that are not
|
||||||
* contained explicitly in the source object itself, such as from a weakmap key
|
* contained explicitly in the source object itself, such as from a weakmap key
|
||||||
* to its value, and from an object being watched by a watchpoint to the
|
* to its value. These "implicit edges" are represented in some other
|
||||||
* watchpoint's closure. These "implicit edges" are represented in some other
|
* container object, such as the weakmap itself. In these cases, calling unmark
|
||||||
* container object, such as the weakmap or the watchpoint itself. In these
|
* gray on an object won't find all of its children.
|
||||||
* cases, calling unmark gray on an object won't find all of its children.
|
|
||||||
*
|
*
|
||||||
* Handling these implicit edges has two parts:
|
* Handling these implicit edges has two parts:
|
||||||
* - A special pass enumerating all of the containers that know about the
|
* - A special pass enumerating all of the containers that know about the
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include "jsgc.h"
|
#include "jsgc.h"
|
||||||
#include "jsprf.h"
|
#include "jsprf.h"
|
||||||
#include "jstypes.h"
|
#include "jstypes.h"
|
||||||
#include "jswatchpoint.h"
|
|
||||||
|
|
||||||
#include "builtin/MapObject.h"
|
#include "builtin/MapObject.h"
|
||||||
#include "frontend/BytecodeCompiler.h"
|
#include "frontend/BytecodeCompiler.h"
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
// |jit-test| error:TypeError
|
|
||||||
|
|
||||||
// Binary: cache/js-dbg-32-29add08d84ae-linux
|
|
||||||
// Flags: -j
|
|
||||||
//
|
|
||||||
this.watch('y', /x/g );
|
|
||||||
for each (y in ['q', 'q', 'q']) continue;
|
|
||||||
gc();
|
|
|
@ -1,6 +0,0 @@
|
||||||
// Binary: cache/js-dbg-64-38754465ffde-linux
|
|
||||||
// Flags:
|
|
||||||
//
|
|
||||||
this.__defineSetter__("x", gc);
|
|
||||||
this.watch("x",function(){return});
|
|
||||||
x = 3;
|
|
|
@ -1,4 +0,0 @@
|
||||||
// Binary: cache/js-dbg-64-9d51f2a931f7-linux
|
|
||||||
// Flags:
|
|
||||||
//
|
|
||||||
({x:function(){}}).watch('x',function(){});
|
|
|
@ -1,9 +0,0 @@
|
||||||
// Binary: cache/js-dbg-64-a6d7a5677b4c-linux
|
|
||||||
// Flags:
|
|
||||||
//
|
|
||||||
this.__defineSetter__("x", function(){})
|
|
||||||
this.watch("x", "".localeCompare)
|
|
||||||
window = x
|
|
||||||
Object.defineProperty(this, "x", ({
|
|
||||||
set: window
|
|
||||||
}))
|
|
|
@ -4,7 +4,6 @@
|
||||||
var o9 = Function.prototype;
|
var o9 = Function.prototype;
|
||||||
var o13 = Array;
|
var o13 = Array;
|
||||||
function f5(o) {
|
function f5(o) {
|
||||||
o.watch('p3', function() {});
|
|
||||||
ox1 = new Proxy(o, {});
|
ox1 = new Proxy(o, {});
|
||||||
}
|
}
|
||||||
f5(o9);
|
f5(o9);
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
// |jit-test| error:TypeError
|
|
||||||
|
|
||||||
// Binary: cache/js-dbg-32-1c8e91b2e3a4-linux
|
|
||||||
// Flags:
|
|
||||||
//
|
|
||||||
a = evalcx("lazy");
|
|
||||||
a.watch("x", function() {});
|
|
||||||
({}).watch("x", function() {});
|
|
||||||
a.__defineGetter__("y", {});
|
|
|
@ -1,9 +0,0 @@
|
||||||
// Binary: cache/js-dbg-32-f951e9151626-linux
|
|
||||||
// Flags: -m -n
|
|
||||||
//
|
|
||||||
o = evalcx("lazy").__proto__
|
|
||||||
gc()
|
|
||||||
try {
|
|
||||||
o.watch()
|
|
||||||
} catch (e) {}
|
|
||||||
o.constructor()
|
|
|
@ -1,10 +0,0 @@
|
||||||
// |jit-test| error:ReferenceError
|
|
||||||
|
|
||||||
// Binary: cache/js-dbg-64-67bf9a4a1f77-linux
|
|
||||||
// Flags: --ion-eager
|
|
||||||
//
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
var a = ['x', 'y'];
|
|
||||||
obj.watch(a[+("0")], counter);
|
|
||||||
})();
|
|
|
@ -1,6 +0,0 @@
|
||||||
// |jit-test| error:TypeError
|
|
||||||
|
|
||||||
// Binary: cache/js-dbg-64-bf8f2961d0cc-linux
|
|
||||||
// Flags:
|
|
||||||
//
|
|
||||||
Object.watch.call(new Uint8ClampedArray, "length", function() {});
|
|
|
@ -1,8 +0,0 @@
|
||||||
gczeal(8, 1)
|
|
||||||
function recurse(x) {
|
|
||||||
recurse;
|
|
||||||
if (x < 20)
|
|
||||||
recurse(x + 1);
|
|
||||||
};
|
|
||||||
this.watch(5, (function () {}))
|
|
||||||
recurse(0)
|
|
|
@ -1,13 +0,0 @@
|
||||||
// Don't crash or assert.
|
|
||||||
|
|
||||||
var d;
|
|
||||||
this.watch("d", eval);
|
|
||||||
(function () {
|
|
||||||
(eval("\
|
|
||||||
(function () {\
|
|
||||||
for (let x = 0; x < 2; ++x) {\
|
|
||||||
d = x\
|
|
||||||
}\
|
|
||||||
})\
|
|
||||||
"))()
|
|
||||||
})()
|
|
|
@ -1,9 +0,0 @@
|
||||||
// |jit-test| error: TypeError
|
|
||||||
// don't assert
|
|
||||||
|
|
||||||
print(this.watch("x",
|
|
||||||
function() {
|
|
||||||
Object.defineProperty(this, "x", ({
|
|
||||||
get: (Int8Array)
|
|
||||||
}))
|
|
||||||
}))(x = /x/)
|
|
|
@ -1,9 +0,0 @@
|
||||||
var n = 0;
|
|
||||||
var a = [];
|
|
||||||
for (var i = 0; i < 20; i++)
|
|
||||||
a[i] = {};
|
|
||||||
a[18].watch("p", function () { n++; });
|
|
||||||
delete a[18].p;
|
|
||||||
for (var i = 0; i < 20; i++)
|
|
||||||
a[i].p = 0;
|
|
||||||
assertEq(n, 1);
|
|
|
@ -1,6 +0,0 @@
|
||||||
// |jit-test| error: TypeError
|
|
||||||
function f(o) {
|
|
||||||
o.watch("x", this);
|
|
||||||
}
|
|
||||||
var c = evalcx("");
|
|
||||||
f(c);
|
|
|
@ -1,12 +0,0 @@
|
||||||
|
|
||||||
done = false;
|
|
||||||
try {
|
|
||||||
function x() {}
|
|
||||||
print(this.watch("d", Object.create))
|
|
||||||
var d = {}
|
|
||||||
} catch (e) {}
|
|
||||||
try {
|
|
||||||
eval("d = ''")
|
|
||||||
done = true;
|
|
||||||
} catch (e) {}
|
|
||||||
assertEq(done, false);
|
|
|
@ -1,6 +1,3 @@
|
||||||
try {
|
|
||||||
this.watch("b", "".substring);
|
|
||||||
} catch(exc1) {}
|
|
||||||
eval("\
|
eval("\
|
||||||
var URI = '';\
|
var URI = '';\
|
||||||
test();\
|
test();\
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
// |jit-test| error:TypeError
|
|
||||||
|
|
||||||
evalcx('').watch("", /()/);
|
|
|
@ -1,7 +0,0 @@
|
||||||
var o = {};
|
|
||||||
o.watch("p", function() { });
|
|
||||||
|
|
||||||
for (var i = 0; i < 10; i++) {
|
|
||||||
o.p = 123;
|
|
||||||
delete o.p;
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
var msg = "";
|
|
||||||
try {
|
|
||||||
this.__defineSetter__('x', Object.create);
|
|
||||||
this.watch('x', function() {});
|
|
||||||
x = 3;
|
|
||||||
} catch (e) {
|
|
||||||
msg = e.toString();
|
|
||||||
}
|
|
||||||
assertEq(msg, "TypeError: undefined is not an object or null");
|
|
|
@ -1,13 +0,0 @@
|
||||||
this.watch("x", Object.create)
|
|
||||||
try {
|
|
||||||
(function() {
|
|
||||||
this.__defineGetter__("x",
|
|
||||||
function() {
|
|
||||||
return this
|
|
||||||
})
|
|
||||||
})()
|
|
||||||
} catch(e) {}
|
|
||||||
Object.defineProperty(x, "x", ({
|
|
||||||
set: Uint16Array
|
|
||||||
}))
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
if (typeof gczeal != "function")
|
|
||||||
gczeal = function() {}
|
|
||||||
|
|
||||||
// don't crash
|
|
||||||
x = (evalcx('lazy'))
|
|
||||||
x.watch("", function () {})
|
|
||||||
gczeal(1)
|
|
||||||
for (w in x) {}
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
s = newGlobal()
|
|
||||||
try {
|
|
||||||
evalcx("\
|
|
||||||
Object.defineProperty(this,\"i\",{enumerable:true,get:function(){t}});\
|
|
||||||
for each(y in this)true\
|
|
||||||
", s)
|
|
||||||
} catch (e) {}
|
|
||||||
try {
|
|
||||||
evalcx("\
|
|
||||||
for(z=0,(7).watch(\"\",eval);;g){\
|
|
||||||
if(z=1){({t:function(){}})\
|
|
||||||
}\
|
|
||||||
", s)
|
|
||||||
} catch (e) {}
|
|
||||||
try {
|
|
||||||
evalcx("\
|
|
||||||
Object.defineProperty(this,\"g2\",{get:function(){return this}});\
|
|
||||||
g2.y()\
|
|
||||||
", s)
|
|
||||||
} catch (e) {}
|
|
|
@ -1,20 +0,0 @@
|
||||||
s = newGlobal()
|
|
||||||
try {
|
|
||||||
evalcx("\
|
|
||||||
Object.defineProperty(this,\"i\",{enumerable:true,get:function(){t}});\
|
|
||||||
for each(y in this)true\
|
|
||||||
", s)
|
|
||||||
} catch (e) {}
|
|
||||||
try {
|
|
||||||
evalcx("\
|
|
||||||
for(z=0,(7).watch(\"\",eval);;g){\
|
|
||||||
if(z=1){({t:function(){}})\
|
|
||||||
}\
|
|
||||||
", s)
|
|
||||||
} catch (e) {}
|
|
||||||
try {
|
|
||||||
evalcx("\
|
|
||||||
Object.defineProperty(this,\"g2\",{get:function(){return this}});\
|
|
||||||
g2.y(\"\")\
|
|
||||||
", s)
|
|
||||||
} catch (e) {}
|
|
|
@ -1,3 +0,0 @@
|
||||||
this.__defineSetter__("x", function(){});
|
|
||||||
this.watch("x", eval);
|
|
||||||
x = 0;
|
|
|
@ -1,7 +0,0 @@
|
||||||
function testNonStubGetter() {
|
|
||||||
{ let [] = []; (this.watch("x", function(p, o, n) { return /a/g.exec(p, o, n); })); };
|
|
||||||
(function () { (eval("(function(){for each (x in [1, 2, 2]);});"))(); })();
|
|
||||||
this.unwatch("x");
|
|
||||||
return "ok";
|
|
||||||
}
|
|
||||||
assertEq(testNonStubGetter(), "ok");
|
|
|
@ -1,7 +0,0 @@
|
||||||
for (var i = 0; i < 5; ++i) {
|
|
||||||
var o = {}
|
|
||||||
Object.defineProperty(o, 'x', { value:"cow", writable:false });
|
|
||||||
var r = o.watch('x', function() {});
|
|
||||||
assertEq(r, undefined);
|
|
||||||
o.x = 4;
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
// Test no assert or crash from outer recorders (bug 465145)
|
|
||||||
function testBug465145() {
|
|
||||||
this.__defineSetter__("x", function(){});
|
|
||||||
this.watch("x", function(){});
|
|
||||||
y = this;
|
|
||||||
for (var z = 0; z < 2; ++z) { x = y };
|
|
||||||
this.__defineSetter__("x", function(){});
|
|
||||||
for (var z = 0; z < 2; ++z) { x = y };
|
|
||||||
}
|
|
||||||
|
|
||||||
function testTrueShiftTrue() {
|
|
||||||
var a = new Array(5);
|
|
||||||
for (var i=0;i<5;++i) a[i] = "" + (true << true);
|
|
||||||
return a.join(",");
|
|
||||||
}
|
|
||||||
assertEq(testTrueShiftTrue(), "2,2,2,2,2");
|
|
|
@ -1,63 +0,0 @@
|
||||||
// Test that the watch handler is not called recursively for the same object
|
|
||||||
// and property.
|
|
||||||
(function() {
|
|
||||||
var obj1 = {}, obj2 = {};
|
|
||||||
var handler_entry_count = 0;
|
|
||||||
var handler_exit_count = 0;
|
|
||||||
|
|
||||||
obj1.watch('x', handler);
|
|
||||||
obj1.watch('y', handler);
|
|
||||||
obj2.watch('x', handler);
|
|
||||||
obj1.x = 1;
|
|
||||||
assertEq(handler_entry_count, 3);
|
|
||||||
assertEq(handler_exit_count, 3);
|
|
||||||
|
|
||||||
function handler(id) {
|
|
||||||
handler_entry_count++;
|
|
||||||
assertEq(handler_exit_count, 0);
|
|
||||||
switch (true) {
|
|
||||||
case this === obj1 && id === "x":
|
|
||||||
assertEq(handler_entry_count, 1);
|
|
||||||
obj2.x = 3;
|
|
||||||
assertEq(handler_exit_count, 2);
|
|
||||||
break;
|
|
||||||
case this === obj2 && id === "x":
|
|
||||||
assertEq(handler_entry_count, 2);
|
|
||||||
obj1.y = 4;
|
|
||||||
assertEq(handler_exit_count, 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assertEq(this, obj1);
|
|
||||||
assertEq(id, "y");
|
|
||||||
assertEq(handler_entry_count, 3);
|
|
||||||
|
|
||||||
// We expect no more watch handler invocations
|
|
||||||
obj1.x = 5;
|
|
||||||
obj1.y = 6;
|
|
||||||
obj2.x = 7;
|
|
||||||
assertEq(handler_exit_count, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++handler_exit_count;
|
|
||||||
assertEq(handler_entry_count, 3);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
// Test that run-away recursion in watch handlers is properly handled.
|
|
||||||
(function() {
|
|
||||||
var obj = {};
|
|
||||||
var i = 0;
|
|
||||||
try {
|
|
||||||
handler();
|
|
||||||
throw new Error("Unreachable");
|
|
||||||
} catch(e) {
|
|
||||||
assertEq(e instanceof InternalError, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handler() {
|
|
||||||
var prop = "a" + ++i;
|
|
||||||
obj.watch(prop, handler);
|
|
||||||
obj[prop] = 2;
|
|
||||||
}
|
|
||||||
})();
|
|
|
@ -1,3 +0,0 @@
|
||||||
(function() {
|
|
||||||
[{ "9": [] }.watch([], function(){})]
|
|
||||||
})()
|
|
|
@ -1,5 +0,0 @@
|
||||||
// |jit-test| error: InternalError: too much recursion
|
|
||||||
(function f() {
|
|
||||||
"".watch(2, function() {});
|
|
||||||
f();
|
|
||||||
})()
|
|
|
@ -1,8 +0,0 @@
|
||||||
// |jit-test| slow
|
|
||||||
function x() {}
|
|
||||||
for (var j = 0; j < 9999; ++j) {
|
|
||||||
(function() {
|
|
||||||
x += x.watch("endsWith", ArrayBuffer);
|
|
||||||
return 0 >> Function(x)
|
|
||||||
})()
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
// |jit-test| error: ReferenceError
|
|
||||||
|
|
||||||
eval("(function() { " + "\
|
|
||||||
var o = {};\
|
|
||||||
o.watch('p', function() { });\
|
|
||||||
for (var i = 0; i < 10; \u5ede ++)\
|
|
||||||
o.p = 123;\
|
|
||||||
" + " })();");
|
|
|
@ -4,4 +4,4 @@ function f(x) {
|
||||||
delete ((x)++);
|
delete ((x)++);
|
||||||
arguments[0] !== undefined;
|
arguments[0] !== undefined;
|
||||||
}
|
}
|
||||||
f(1, x = [f.ArrayBuffer,unwatch.Int32Array], this, this, this) ;
|
f(1, x = [f.ArrayBuffer, undefined], this, this, this) ;
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
Object.defineProperty(Object.prototype, 'x', {
|
|
||||||
set: function() { evalcx('lazy'); }
|
|
||||||
});
|
|
||||||
var obj = {};
|
|
||||||
obj.watch("x", function (id, oldval, newval) {});
|
|
||||||
for (var str in 'A') {
|
|
||||||
obj.x = 1;
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
Object.defineProperty(Object.prototype, 'x', {
|
|
||||||
set: function() { evalcx('lazy'); }
|
|
||||||
});
|
|
||||||
var obj = {};
|
|
||||||
var prot = {};
|
|
||||||
obj.__proto__ = prot;
|
|
||||||
obj.watch("x", function (id, oldval, newval) {});
|
|
||||||
for (var str in 'A') {
|
|
||||||
obj.x = 1;
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
var flag = 0;
|
|
||||||
var a = {};
|
|
||||||
Object.defineProperty(a, "value", {set: function(x) {}});
|
|
||||||
a.watch("value", function(){flag++;});
|
|
||||||
|
|
||||||
for(var i = 0; i < 100; i++) {
|
|
||||||
a.value = i;
|
|
||||||
assertEq(flag, i+1);
|
|
||||||
}
|
|
|
@ -7,7 +7,6 @@ Object.defineProperty(arr, 0, {
|
||||||
glob.__proto__;
|
glob.__proto__;
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
this.watch("s", function() {});
|
|
||||||
try {
|
try {
|
||||||
arr.pop();
|
arr.pop();
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
(function () {
|
|
||||||
var a;
|
|
||||||
eval("for(w in ((function(x,y){b:0})())) ;");
|
|
||||||
})();
|
|
||||||
|
|
||||||
this.__defineSetter__("l", function() { gc() });
|
|
||||||
this.watch("l", function(x) { yield {} });
|
|
||||||
l = true;
|
|
|
@ -1,7 +0,0 @@
|
||||||
(function() {
|
|
||||||
for (a = 0; a < 2; a++)
|
|
||||||
''.watch("", function() {})
|
|
||||||
})()
|
|
||||||
|
|
||||||
/* Don't crash or assert. */
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ function f() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})(/x/)))
|
})(/x/)))
|
||||||
for (z = 0; z < 100; x.unwatch(), z++)
|
|
||||||
for (e in [0]) {
|
for (e in [0]) {
|
||||||
gczeal(2)
|
gczeal(2)
|
||||||
} ( [1,2,3])("")
|
} ( [1,2,3])("")
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
// vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
this.watch("x", function() {
|
|
||||||
count++;
|
|
||||||
});
|
|
||||||
for(var i=0; i<10; i++) {
|
|
||||||
x = 2;
|
|
||||||
}
|
|
||||||
assertEq(count, 10);
|
|
|
@ -1,7 +0,0 @@
|
||||||
var o = {};
|
|
||||||
for(var i=0; i<5; i++) {
|
|
||||||
o.p = 2;
|
|
||||||
o.watch("p", function() { });
|
|
||||||
o.p = 2;
|
|
||||||
delete o.p;
|
|
||||||
}
|
|
|
@ -118,7 +118,6 @@ for(var o2 in f5) {
|
||||||
f2(o5);
|
f2(o5);
|
||||||
f2(o5);
|
f2(o5);
|
||||||
f0(o3);
|
f0(o3);
|
||||||
o9.watch('p3', function() {});
|
|
||||||
o8[o8] = o8;
|
o8[o8] = o8;
|
||||||
f0(o5);
|
f0(o5);
|
||||||
f1(o6);
|
f1(o6);
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
(function() {
|
|
||||||
for (a = 0; a < 2; a++)
|
|
||||||
''.watch("", function() {})
|
|
||||||
})()
|
|
|
@ -1,3 +0,0 @@
|
||||||
for each(let w in [[], 0, [], 0]) {
|
|
||||||
w.unwatch()
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
// assignments to watched objects must not be cached
|
|
||||||
var obj = {x: 0};
|
|
||||||
var hits = 0;
|
|
||||||
obj.watch("x", function (id, oldval, newval) { hits++; return newval; });
|
|
||||||
for (var i = 0; i < 10; i++)
|
|
||||||
obj.x = i;
|
|
||||||
assertEq(hits, 10);
|
|
|
@ -1,17 +0,0 @@
|
||||||
// assignments to watched objects must not be traced
|
|
||||||
var hits = 0;
|
|
||||||
function counter(id, oldval, newval) {
|
|
||||||
hits++;
|
|
||||||
return newval;
|
|
||||||
}
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
var obj = {x: 0, y: 0};
|
|
||||||
var a = ['x', 'y'];
|
|
||||||
obj.watch('z', counter);
|
|
||||||
for (var i = 0; i < 14; i++) {
|
|
||||||
obj.watch(a[+(i > 8)], counter);
|
|
||||||
obj.y = i;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
assertEq(hits, 5);
|
|
|
@ -1,8 +0,0 @@
|
||||||
// assignments to watched properties via ++ must not be cached
|
|
||||||
var obj = {x: 0};
|
|
||||||
var hits = 0;
|
|
||||||
obj.watch("x", function (id, oldval, newval) { hits++; return newval; });
|
|
||||||
for (var i = 0; i < 10; i++)
|
|
||||||
obj.x++;
|
|
||||||
assertEq(hits, 10);
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
// assignments to watched properties via ++ must not be traced
|
|
||||||
var hits = 0;
|
|
||||||
function counter(id, oldval, newval) {
|
|
||||||
hits++;
|
|
||||||
return newval;
|
|
||||||
}
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
var obj = {x: 0, y: 0};
|
|
||||||
var a = ['x', 'y'];
|
|
||||||
obj.watch('z', counter);
|
|
||||||
for (var i = 0; i < 14; i++) {
|
|
||||||
obj.watch(a[+(i > 8)], counter);
|
|
||||||
obj.y++;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
assertEq(hits, 5);
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
// assignment to watched global properties must not be cached
|
|
||||||
x = 0;
|
|
||||||
var hits = 0;
|
|
||||||
this.watch("x", function (id, oldval, newval) { hits++; return newval; });
|
|
||||||
for (var i = 0; i < 10; i++)
|
|
||||||
x = i;
|
|
||||||
assertEq(hits, 10);
|
|
|
@ -1,19 +0,0 @@
|
||||||
// assignment to watched global properties must not be traced
|
|
||||||
var hits = 0;
|
|
||||||
function counter(id, oldval, newval) {
|
|
||||||
hits++;
|
|
||||||
return newval;
|
|
||||||
}
|
|
||||||
|
|
||||||
var x = 0;
|
|
||||||
var y = 0;
|
|
||||||
(function () {
|
|
||||||
var a = ['x', 'y'];
|
|
||||||
this.watch('z', counter);
|
|
||||||
for (var i = 0; i < 14; i++) {
|
|
||||||
this.watch(a[+(i > 8)], counter);
|
|
||||||
y = 1;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
assertEq(hits, 5);
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
// assignment to watched global properties must not be traced
|
|
||||||
var hits = 0;
|
|
||||||
function counter(id, oldval, newval) {
|
|
||||||
hits++;
|
|
||||||
return newval;
|
|
||||||
}
|
|
||||||
|
|
||||||
var x = 0;
|
|
||||||
var y = 0;
|
|
||||||
function f() {
|
|
||||||
var a = [{}, this];
|
|
||||||
for (var i = 0; i < 14; i++) {
|
|
||||||
print(shapeOf(this));
|
|
||||||
Object.prototype.watch.call(a[+(i > 8)], "y", counter);
|
|
||||||
y++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f();
|
|
||||||
assertEq(hits, 5);
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
// adding assignment + watchpoint vs. caching
|
|
||||||
var hits = 0;
|
|
||||||
var obj = {};
|
|
||||||
obj.watch("x", function (id, oldval, newval) { hits++; return newval; });
|
|
||||||
for (var i = 0; i < 10; i++) {
|
|
||||||
obj.x = 1;
|
|
||||||
delete obj.x;
|
|
||||||
}
|
|
||||||
assertEq(hits, 10);
|
|
|
@ -1,27 +0,0 @@
|
||||||
// test against future pic support for symbols
|
|
||||||
|
|
||||||
// assignments to watched objects must not be cached
|
|
||||||
var obj = {};
|
|
||||||
var x = Symbol.for("x");
|
|
||||||
obj[x] = 0;
|
|
||||||
var hits = 0;
|
|
||||||
obj.watch(x, function (id, oldval, newval) { hits++; return newval; });
|
|
||||||
for (var i = 0; i < 10; i++)
|
|
||||||
obj[x] = i;
|
|
||||||
assertEq(hits, 10);
|
|
||||||
|
|
||||||
// assignments to watched properties via ++ must not be cached
|
|
||||||
hits = 0;
|
|
||||||
for (var i = 0; i < 10; i++)
|
|
||||||
obj[x]++;
|
|
||||||
assertEq(hits, 10);
|
|
||||||
|
|
||||||
// adding assignment + watchpoint vs. caching
|
|
||||||
hits = 0;
|
|
||||||
obj = {};
|
|
||||||
obj.watch(x, function (id, oldval, newval) { hits++; return newval; });
|
|
||||||
for (var i = 0; i < 10; i++) {
|
|
||||||
obj[x] = 1;
|
|
||||||
delete obj[x];
|
|
||||||
}
|
|
||||||
assertEq(hits, 10);
|
|
|
@ -1,14 +0,0 @@
|
||||||
// |jit-test| allow-oom
|
|
||||||
enableSPSProfiling();
|
|
||||||
loadFile('\
|
|
||||||
for (var i = 0; i < 2; i++) {\
|
|
||||||
obj = { m: function () {} };\
|
|
||||||
obj.watch("m", function () { float32 = 0 + obj.foo; });\
|
|
||||||
obj.m = 0;\
|
|
||||||
}\
|
|
||||||
');
|
|
||||||
gcparam("maxBytes", gcparam("gcBytes") + (1)*1024);
|
|
||||||
newGlobal("same-compartment");
|
|
||||||
function loadFile(lfVarx) {
|
|
||||||
evaluate(lfVarx, { noScriptRval : true, isRunOnce : true });
|
|
||||||
}
|
|
|
@ -4053,9 +4053,6 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!*attached);
|
MOZ_ASSERT(!*attached);
|
||||||
|
|
||||||
if (obj->watched())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
RootedShape shape(cx);
|
RootedShape shape(cx);
|
||||||
RootedObject holder(cx);
|
RootedObject holder(cx);
|
||||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
|
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
|
||||||
|
@ -4151,9 +4148,6 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||||
MOZ_ASSERT(!*attached);
|
MOZ_ASSERT(!*attached);
|
||||||
MOZ_ASSERT(!*isTemporarilyUnoptimizable);
|
MOZ_ASSERT(!*isTemporarilyUnoptimizable);
|
||||||
|
|
||||||
if (obj->watched())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
RootedShape shape(cx);
|
RootedShape shape(cx);
|
||||||
RootedObject holder(cx);
|
RootedObject holder(cx);
|
||||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
|
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
|
||||||
|
|
|
@ -3232,7 +3232,7 @@ SetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript*
|
||||||
MOZ_ASSERT(!*emitted);
|
MOZ_ASSERT(!*emitted);
|
||||||
MOZ_ASSERT(!*tryNativeAddSlot);
|
MOZ_ASSERT(!*tryNativeAddSlot);
|
||||||
|
|
||||||
if (!canAttachStub() || obj->watched())
|
if (!canAttachStub())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Fail cache emission if the object is frozen
|
// Fail cache emission if the object is frozen
|
||||||
|
@ -3897,9 +3897,6 @@ IsDenseElementSetInlineable(JSObject* obj, const Value& idval, const ConstantOrR
|
||||||
if (!obj->is<ArrayObject>())
|
if (!obj->is<ArrayObject>())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (obj->watched())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!idval.isInt32())
|
if (!idval.isInt32())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,6 @@ MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, JSEXN_TYPEERR, "{0} requires more than
|
||||||
MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
|
MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
|
||||||
MSG_DEF(JSMSG_NO_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} has no constructor")
|
MSG_DEF(JSMSG_NO_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} has no constructor")
|
||||||
MSG_DEF(JSMSG_BAD_SORT_ARG, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument")
|
MSG_DEF(JSMSG_BAD_SORT_ARG, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument")
|
||||||
MSG_DEF(JSMSG_CANT_WATCH, 1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}")
|
|
||||||
MSG_DEF(JSMSG_READ_ONLY, 1, JSEXN_TYPEERR, "{0} is read-only")
|
MSG_DEF(JSMSG_READ_ONLY, 1, JSEXN_TYPEERR, "{0} is read-only")
|
||||||
MSG_DEF(JSMSG_CANT_DELETE, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
|
MSG_DEF(JSMSG_CANT_DELETE, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
|
||||||
MSG_DEF(JSMSG_CANT_TRUNCATE_ARRAY, 0, JSEXN_TYPEERR, "can't delete non-configurable array element")
|
MSG_DEF(JSMSG_CANT_TRUNCATE_ARRAY, 0, JSEXN_TYPEERR, "can't delete non-configurable array element")
|
||||||
|
@ -72,7 +71,6 @@ MSG_DEF(JSMSG_UNDEFINED_PROP, 1, JSEXN_REFERENCEERR, "reference to unde
|
||||||
MSG_DEF(JSMSG_INVALID_MAP_ITERABLE, 1, JSEXN_TYPEERR, "iterable for {0} should have array-like objects")
|
MSG_DEF(JSMSG_INVALID_MAP_ITERABLE, 1, JSEXN_TYPEERR, "iterable for {0} should have array-like objects")
|
||||||
MSG_DEF(JSMSG_NESTING_GENERATOR, 0, JSEXN_TYPEERR, "already executing generator")
|
MSG_DEF(JSMSG_NESTING_GENERATOR, 0, JSEXN_TYPEERR, "already executing generator")
|
||||||
MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
|
MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
|
||||||
MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_WARN, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead")
|
|
||||||
MSG_DEF(JSMSG_ARRAYBUFFER_SLICE_DEPRECATED, 0, JSEXN_WARN, "ArrayBuffer.slice is deprecated; use ArrayBuffer.prototype.slice instead")
|
MSG_DEF(JSMSG_ARRAYBUFFER_SLICE_DEPRECATED, 0, JSEXN_WARN, "ArrayBuffer.slice is deprecated; use ArrayBuffer.prototype.slice instead")
|
||||||
MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 1, JSEXN_TYPEERR, "bad surrogate character {0}")
|
MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 1, JSEXN_TYPEERR, "bad surrogate character {0}")
|
||||||
MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
|
MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
#include "jsstr.h"
|
#include "jsstr.h"
|
||||||
#include "jstypes.h"
|
#include "jstypes.h"
|
||||||
#include "jsutil.h"
|
#include "jsutil.h"
|
||||||
#include "jswatchpoint.h"
|
|
||||||
#include "jsweakmap.h"
|
#include "jsweakmap.h"
|
||||||
#include "jswrapper.h"
|
#include "jswrapper.h"
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
#include "jsstr.h"
|
#include "jsstr.h"
|
||||||
#include "jstypes.h"
|
#include "jstypes.h"
|
||||||
#include "jswatchpoint.h"
|
|
||||||
|
|
||||||
#include "gc/Marking.h"
|
#include "gc/Marking.h"
|
||||||
#include "jit/Ion.h"
|
#include "jit/Ion.h"
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
#include "jsgc.h"
|
#include "jsgc.h"
|
||||||
#include "jsiter.h"
|
#include "jsiter.h"
|
||||||
#include "jswatchpoint.h"
|
|
||||||
#include "jswrapper.h"
|
#include "jswrapper.h"
|
||||||
|
|
||||||
#include "gc/Marking.h"
|
#include "gc/Marking.h"
|
||||||
|
@ -76,7 +75,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
|
||||||
gcIncomingGrayPointers(nullptr),
|
gcIncomingGrayPointers(nullptr),
|
||||||
debugModeBits(0),
|
debugModeBits(0),
|
||||||
randomKeyGenerator_(runtime_->forkRandomKeyGenerator()),
|
randomKeyGenerator_(runtime_->forkRandomKeyGenerator()),
|
||||||
watchpointMap(nullptr),
|
|
||||||
scriptCountsMap(nullptr),
|
scriptCountsMap(nullptr),
|
||||||
debugScriptMap(nullptr),
|
debugScriptMap(nullptr),
|
||||||
debugEnvs(nullptr),
|
debugEnvs(nullptr),
|
||||||
|
@ -103,7 +101,6 @@ JSCompartment::~JSCompartment()
|
||||||
rt->lcovOutput.writeLCovResult(lcovOutput);
|
rt->lcovOutput.writeLCovResult(lcovOutput);
|
||||||
|
|
||||||
js_delete(jitCompartment_);
|
js_delete(jitCompartment_);
|
||||||
js_delete(watchpointMap);
|
|
||||||
js_delete(scriptCountsMap);
|
js_delete(scriptCountsMap);
|
||||||
js_delete(debugScriptMap);
|
js_delete(debugScriptMap);
|
||||||
js_delete(debugEnvs);
|
js_delete(debugEnvs);
|
||||||
|
@ -662,12 +659,6 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t
|
||||||
if (traceOrMark == js::gc::GCRuntime::MarkRuntime && !zone()->isCollecting())
|
if (traceOrMark == js::gc::GCRuntime::MarkRuntime && !zone()->isCollecting())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// During a GC, these are treated as weak pointers.
|
|
||||||
if (traceOrMark == js::gc::GCRuntime::TraceRuntime) {
|
|
||||||
if (watchpointMap)
|
|
||||||
watchpointMap->markAll(trc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark debug scopes, if present */
|
/* Mark debug scopes, if present */
|
||||||
if (debugEnvs)
|
if (debugEnvs)
|
||||||
debugEnvs->mark(trc);
|
debugEnvs->mark(trc);
|
||||||
|
@ -712,9 +703,6 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t
|
||||||
void
|
void
|
||||||
JSCompartment::finishRoots()
|
JSCompartment::finishRoots()
|
||||||
{
|
{
|
||||||
if (watchpointMap)
|
|
||||||
watchpointMap->clear();
|
|
||||||
|
|
||||||
if (debugEnvs)
|
if (debugEnvs)
|
||||||
debugEnvs->finish();
|
debugEnvs->finish();
|
||||||
|
|
||||||
|
|
|
@ -282,7 +282,6 @@ class MOZ_RAII AutoSetNewObjectMetadata : private JS::CustomAutoRooter
|
||||||
namespace js {
|
namespace js {
|
||||||
class DebugEnvironments;
|
class DebugEnvironments;
|
||||||
class ObjectWeakMap;
|
class ObjectWeakMap;
|
||||||
class WatchpointMap;
|
|
||||||
class WeakMapBase;
|
class WeakMapBase;
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
|
@ -811,8 +810,6 @@ struct JSCompartment
|
||||||
void sweepBreakpoints(js::FreeOp* fop);
|
void sweepBreakpoints(js::FreeOp* fop);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
js::WatchpointMap* watchpointMap;
|
|
||||||
|
|
||||||
js::ScriptCountsMap* scriptCountsMap;
|
js::ScriptCountsMap* scriptCountsMap;
|
||||||
|
|
||||||
js::DebugScriptMap* debugScriptMap;
|
js::DebugScriptMap* debugScriptMap;
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include "jsgc.h"
|
#include "jsgc.h"
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
#include "jsprf.h"
|
#include "jsprf.h"
|
||||||
#include "jswatchpoint.h"
|
|
||||||
#include "jsweakmap.h"
|
#include "jsweakmap.h"
|
||||||
#include "jswrapper.h"
|
#include "jswrapper.h"
|
||||||
|
|
||||||
|
@ -579,7 +578,6 @@ void
|
||||||
js::TraceWeakMaps(WeakMapTracer* trc)
|
js::TraceWeakMaps(WeakMapTracer* trc)
|
||||||
{
|
{
|
||||||
WeakMapBase::traceAllMappings(trc);
|
WeakMapBase::traceAllMappings(trc);
|
||||||
WatchpointMap::traceAll(trc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern JS_FRIEND_API(bool)
|
extern JS_FRIEND_API(bool)
|
||||||
|
|
|
@ -2110,30 +2110,6 @@ JS_FRIEND_API(void*)
|
||||||
JS_GetDataViewData(JSObject* obj, const JS::AutoCheckCannotGC&);
|
JS_GetDataViewData(JSObject* obj, const JS::AutoCheckCannotGC&);
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the
|
|
||||||
* property |id|, using the callable object |callable| as the function to be
|
|
||||||
* called for notifications.
|
|
||||||
*
|
|
||||||
* This is an internal function exposed -- temporarily -- only so that DOM
|
|
||||||
* proxies can be watchable. Don't use it! We'll soon kill off the
|
|
||||||
* Object.prototype.{,un}watch functions, at which point this will go too.
|
|
||||||
*/
|
|
||||||
extern JS_FRIEND_API(bool)
|
|
||||||
WatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a watchpoint -- in the Object.prototype.watch sense -- from |obj| for
|
|
||||||
* the property |id|.
|
|
||||||
*
|
|
||||||
* This is an internal function exposed -- temporarily -- only so that DOM
|
|
||||||
* proxies can be watchable. Don't use it! We'll soon kill off the
|
|
||||||
* Object.prototype.{,un}watch functions, at which point this will go too.
|
|
||||||
*/
|
|
||||||
extern JS_FRIEND_API(bool)
|
|
||||||
UnwatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id);
|
|
||||||
|
|
||||||
namespace jit {
|
namespace jit {
|
||||||
|
|
||||||
enum class InlinableNative : uint16_t;
|
enum class InlinableNative : uint16_t;
|
||||||
|
|
|
@ -207,7 +207,6 @@
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
#include "jstypes.h"
|
#include "jstypes.h"
|
||||||
#include "jsutil.h"
|
#include "jsutil.h"
|
||||||
#include "jswatchpoint.h"
|
|
||||||
#include "jsweakmap.h"
|
#include "jsweakmap.h"
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
# include "jswin.h"
|
# include "jswin.h"
|
||||||
|
@ -2392,11 +2391,6 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAccess
|
||||||
Debugger::markIncomingCrossCompartmentEdges(&trc);
|
Debugger::markIncomingCrossCompartmentEdges(&trc);
|
||||||
|
|
||||||
WeakMapBase::markAll(zone, &trc);
|
WeakMapBase::markAll(zone, &trc);
|
||||||
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
|
|
||||||
c->trace(&trc);
|
|
||||||
if (c->watchpointMap)
|
|
||||||
c->watchpointMap->markAll(&trc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark all gray roots, making sure we call the trace callback to get the
|
// Mark all gray roots, making sure we call the trace callback to get the
|
||||||
// current set.
|
// current set.
|
||||||
|
@ -2405,7 +2399,6 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sweep everything to fix up weak pointers
|
// Sweep everything to fix up weak pointers
|
||||||
WatchpointMap::sweepAll(rt);
|
|
||||||
Debugger::sweepAll(rt->defaultFreeOp());
|
Debugger::sweepAll(rt->defaultFreeOp());
|
||||||
jit::JitRuntime::SweepJitcodeGlobalTable(rt);
|
jit::JitRuntime::SweepJitcodeGlobalTable(rt);
|
||||||
rt->gc.sweepZoneAfterCompacting(zone);
|
rt->gc.sweepZoneAfterCompacting(zone);
|
||||||
|
@ -3850,10 +3843,6 @@ GCRuntime::markWeakReferences(gcstats::Phase phase)
|
||||||
for (ZoneIterT zone(rt); !zone.done(); zone.next())
|
for (ZoneIterT zone(rt); !zone.done(); zone.next())
|
||||||
markedAny |= WeakMapBase::markZoneIteratively(zone, &marker);
|
markedAny |= WeakMapBase::markZoneIteratively(zone, &marker);
|
||||||
}
|
}
|
||||||
for (CompartmentsIterT<ZoneIterT> c(rt); !c.done(); c.next()) {
|
|
||||||
if (c->watchpointMap)
|
|
||||||
markedAny |= c->watchpointMap->markIteratively(&marker);
|
|
||||||
}
|
|
||||||
markedAny |= Debugger::markAllIteratively(&marker);
|
markedAny |= Debugger::markAllIteratively(&marker);
|
||||||
markedAny |= jit::JitRuntime::MarkJitcodeGlobalTableIteratively(&marker);
|
markedAny |= jit::JitRuntime::MarkJitcodeGlobalTableIteratively(&marker);
|
||||||
|
|
||||||
|
@ -4625,9 +4614,6 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock)
|
||||||
// Bug 1071218: the following two methods have not yet been
|
// Bug 1071218: the following two methods have not yet been
|
||||||
// refactored to work on a single zone-group at once.
|
// refactored to work on a single zone-group at once.
|
||||||
|
|
||||||
// Collect watch points associated with unreachable objects.
|
|
||||||
WatchpointMap::sweepAll(rt);
|
|
||||||
|
|
||||||
// Detach unreachable debuggers and global objects from each other.
|
// Detach unreachable debuggers and global objects from each other.
|
||||||
Debugger::sweepAll(&fop);
|
Debugger::sweepAll(&fop);
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include "jsstr.h"
|
#include "jsstr.h"
|
||||||
#include "jstypes.h"
|
#include "jstypes.h"
|
||||||
#include "jsutil.h"
|
#include "jsutil.h"
|
||||||
#include "jswatchpoint.h"
|
|
||||||
#include "jswin.h"
|
#include "jswin.h"
|
||||||
#include "jswrapper.h"
|
#include "jswrapper.h"
|
||||||
|
|
||||||
|
@ -1011,13 +1010,7 @@ js::CreateThisForFunction(JSContext* cx, HandleObject callee, HandleObject newTa
|
||||||
JSObject::nonNativeSetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
|
JSObject::nonNativeSetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
|
||||||
HandleValue receiver, ObjectOpResult& result)
|
HandleValue receiver, ObjectOpResult& result)
|
||||||
{
|
{
|
||||||
RootedValue value(cx, v);
|
return obj->getOpsSetProperty()(cx, obj, id, v, receiver, result);
|
||||||
if (MOZ_UNLIKELY(obj->watched())) {
|
|
||||||
WatchpointMap* wpmap = cx->compartment()->watchpointMap;
|
|
||||||
if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &value))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return obj->getOpsSetProperty()(cx, obj, id, value, receiver, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
|
@ -2795,68 +2788,6 @@ js::GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
js::WatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id, JS::HandleObject callable)
|
|
||||||
{
|
|
||||||
RootedObject obj(cx, ToWindowIfWindowProxy(origObj));
|
|
||||||
if (obj->isNative()) {
|
|
||||||
// Use sparse indexes for watched objects, as dense elements can be
|
|
||||||
// written to without checking the watchpoint map.
|
|
||||||
if (!NativeObject::sparsifyDenseElements(cx, obj.as<NativeObject>()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
MarkTypePropertyNonData(cx, obj, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
WatchpointMap* wpmap = cx->compartment()->watchpointMap;
|
|
||||||
if (!wpmap) {
|
|
||||||
wpmap = cx->runtime()->new_<WatchpointMap>();
|
|
||||||
if (!wpmap || !wpmap->init()) {
|
|
||||||
ReportOutOfMemory(cx);
|
|
||||||
js_delete(wpmap);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cx->compartment()->watchpointMap = wpmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wpmap->watch(cx, obj, id, js::WatchHandler, callable);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
js::UnwatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id)
|
|
||||||
{
|
|
||||||
// Looking in the map for an unsupported object will never hit, so we don't
|
|
||||||
// need to check for nativeness or watchable-ness here.
|
|
||||||
RootedObject obj(cx, ToWindowIfWindowProxy(origObj));
|
|
||||||
if (WatchpointMap* wpmap = cx->compartment()->watchpointMap)
|
|
||||||
wpmap->unwatch(obj, id, nullptr, nullptr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
js::WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable)
|
|
||||||
{
|
|
||||||
if (WatchOp op = obj->getOpsWatch())
|
|
||||||
return op(cx, obj, id, callable);
|
|
||||||
|
|
||||||
if (!obj->isNative() || obj->is<TypedArrayObject>()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_WATCH,
|
|
||||||
obj->getClass()->name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return WatchGuts(cx, obj, id, callable);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
js::UnwatchProperty(JSContext* cx, HandleObject obj, HandleId id)
|
|
||||||
{
|
|
||||||
if (UnwatchOp op = obj->getOpsUnwatch())
|
|
||||||
return op(cx, obj, id);
|
|
||||||
|
|
||||||
return UnwatchGuts(cx, obj, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
js::GetObjectClassName(JSContext* cx, HandleObject obj)
|
js::GetObjectClassName(JSContext* cx, HandleObject obj)
|
||||||
{
|
{
|
||||||
|
@ -3416,7 +3347,6 @@ JSObject::dump(FILE* fp) const
|
||||||
if (obj->isBoundFunction()) fprintf(fp, " bound_function");
|
if (obj->isBoundFunction()) fprintf(fp, " bound_function");
|
||||||
if (obj->isQualifiedVarObj()) fprintf(fp, " varobj");
|
if (obj->isQualifiedVarObj()) fprintf(fp, " varobj");
|
||||||
if (obj->isUnqualifiedVarObj()) fprintf(fp, " unqualified_varobj");
|
if (obj->isUnqualifiedVarObj()) fprintf(fp, " unqualified_varobj");
|
||||||
if (obj->watched()) fprintf(fp, " watched");
|
|
||||||
if (obj->isIteratedSingleton()) fprintf(fp, " iterated_singleton");
|
if (obj->isIteratedSingleton()) fprintf(fp, " iterated_singleton");
|
||||||
if (obj->isNewGroupUnknown()) fprintf(fp, " new_type_unknown");
|
if (obj->isNewGroupUnknown()) fprintf(fp, " new_type_unknown");
|
||||||
if (obj->hasUncacheableProto()) fprintf(fp, " has_uncacheable_proto");
|
if (obj->hasUncacheableProto()) fprintf(fp, " has_uncacheable_proto");
|
||||||
|
|
|
@ -141,8 +141,6 @@ class JSObject : public js::gc::Cell
|
||||||
js::GetOwnPropertyOp getOpsGetOwnPropertyDescriptor()
|
js::GetOwnPropertyOp getOpsGetOwnPropertyDescriptor()
|
||||||
const { return getClass()->getOpsGetOwnPropertyDescriptor(); }
|
const { return getClass()->getOpsGetOwnPropertyDescriptor(); }
|
||||||
js::DeletePropertyOp getOpsDeleteProperty() const { return getClass()->getOpsDeleteProperty(); }
|
js::DeletePropertyOp getOpsDeleteProperty() const { return getClass()->getOpsDeleteProperty(); }
|
||||||
js::WatchOp getOpsWatch() const { return getClass()->getOpsWatch(); }
|
|
||||||
js::UnwatchOp getOpsUnwatch() const { return getClass()->getOpsUnwatch(); }
|
|
||||||
js::GetElementsOp getOpsGetElements() const { return getClass()->getOpsGetElements(); }
|
js::GetElementsOp getOpsGetElements() const { return getClass()->getOpsGetElements(); }
|
||||||
JSNewEnumerateOp getOpsEnumerate() const { return getClass()->getOpsEnumerate(); }
|
JSNewEnumerateOp getOpsEnumerate() const { return getClass()->getOpsEnumerate(); }
|
||||||
JSFunToStringOp getOpsFunToString() const { return getClass()->getOpsFunToString(); }
|
JSFunToStringOp getOpsFunToString() const { return getClass()->getOpsFunToString(); }
|
||||||
|
@ -221,11 +219,6 @@ class JSObject : public js::gc::Cell
|
||||||
inline bool isBoundFunction() const;
|
inline bool isBoundFunction() const;
|
||||||
inline bool hasSpecialEquality() const;
|
inline bool hasSpecialEquality() const;
|
||||||
|
|
||||||
inline bool watched() const;
|
|
||||||
static bool setWatched(js::ExclusiveContext* cx, JS::HandleObject obj) {
|
|
||||||
return setFlags(cx, obj, js::BaseShape::WATCHED, GENERATE_SHAPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A "qualified" varobj is the object on which "qualified" variable
|
// A "qualified" varobj is the object on which "qualified" variable
|
||||||
// declarations (i.e., those defined with "var") are kept.
|
// declarations (i.e., those defined with "var") are kept.
|
||||||
//
|
//
|
||||||
|
@ -1032,21 +1025,6 @@ extern bool
|
||||||
DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
|
DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
|
||||||
DefineAsIntrinsic intrinsic);
|
DefineAsIntrinsic intrinsic);
|
||||||
|
|
||||||
/*
|
|
||||||
* Set a watchpoint: a synchronous callback when the given property of the
|
|
||||||
* given object is set.
|
|
||||||
*
|
|
||||||
* Watchpoints are nonstandard and do not fit in well with the way ES6
|
|
||||||
* specifies [[Set]]. They are also insufficient for implementing
|
|
||||||
* Object.observe.
|
|
||||||
*/
|
|
||||||
extern bool
|
|
||||||
WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
|
|
||||||
|
|
||||||
/* Clear a watchpoint. */
|
|
||||||
extern bool
|
|
||||||
UnwatchProperty(JSContext* cx, HandleObject obj, HandleId id);
|
|
||||||
|
|
||||||
/* ES6 draft rev 36 (2015 March 17) 7.1.1 ToPrimitive(vp[, preferredType]) */
|
/* ES6 draft rev 36 (2015 March 17) 7.1.1 ToPrimitive(vp[, preferredType]) */
|
||||||
extern bool
|
extern bool
|
||||||
ToPrimitiveSlow(JSContext* cx, JSType hint, MutableHandleValue vp);
|
ToPrimitiveSlow(JSContext* cx, JSType hint, MutableHandleValue vp);
|
||||||
|
|
|
@ -463,12 +463,6 @@ JSObject::isBoundFunction() const
|
||||||
return is<JSFunction>() && as<JSFunction>().isBoundFunction();
|
return is<JSFunction>() && as<JSFunction>().isBoundFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
|
||||||
JSObject::watched() const
|
|
||||||
{
|
|
||||||
return hasAllFlags(js::BaseShape::WATCHED);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
JSObject::isDelegate() const
|
JSObject::isDelegate() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
*/
|
*/
|
||||||
#define JS_HAS_STR_HTML_HELPERS 1 /* (no longer used) */
|
#define JS_HAS_STR_HTML_HELPERS 1 /* (no longer used) */
|
||||||
#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */
|
#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */
|
||||||
#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */
|
|
||||||
#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */
|
#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */
|
||||||
#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */
|
#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */
|
||||||
#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */
|
#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */
|
||||||
|
|
|
@ -1,246 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
||||||
* 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/. */
|
|
||||||
|
|
||||||
#include "jswatchpoint.h"
|
|
||||||
|
|
||||||
#include "jsatom.h"
|
|
||||||
#include "jscompartment.h"
|
|
||||||
#include "jsfriendapi.h"
|
|
||||||
|
|
||||||
#include "gc/Marking.h"
|
|
||||||
#include "vm/Shape.h"
|
|
||||||
|
|
||||||
#include "jsgcinlines.h"
|
|
||||||
|
|
||||||
using namespace js;
|
|
||||||
using namespace js::gc;
|
|
||||||
|
|
||||||
inline HashNumber
|
|
||||||
WatchKeyHasher::hash(const Lookup& key)
|
|
||||||
{
|
|
||||||
return MovableCellHasher<PreBarrieredObject>::hash(key.object) ^ HashId(key.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class AutoEntryHolder {
|
|
||||||
typedef WatchpointMap::Map Map;
|
|
||||||
Generation gen;
|
|
||||||
Map& map;
|
|
||||||
Map::Ptr p;
|
|
||||||
RootedObject obj;
|
|
||||||
RootedId id;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AutoEntryHolder(JSContext* cx, Map& map, Map::Ptr p)
|
|
||||||
: gen(map.generation()), map(map), p(p), obj(cx, p->key().object), id(cx, p->key().id)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!p->value().held);
|
|
||||||
p->value().held = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
~AutoEntryHolder() {
|
|
||||||
if (gen != map.generation())
|
|
||||||
p = map.lookup(WatchKey(obj, id));
|
|
||||||
if (p)
|
|
||||||
p->value().held = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} /* anonymous namespace */
|
|
||||||
|
|
||||||
bool
|
|
||||||
WatchpointMap::init()
|
|
||||||
{
|
|
||||||
return map.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
WatchpointMap::watch(JSContext* cx, HandleObject obj, HandleId id,
|
|
||||||
JSWatchPointHandler handler, HandleObject closure)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id));
|
|
||||||
|
|
||||||
if (!JSObject::setWatched(cx, obj))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Watchpoint w(handler, closure, false);
|
|
||||||
if (!map.put(WatchKey(obj, id), w)) {
|
|
||||||
ReportOutOfMemory(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* For generational GC, we don't need to post-barrier writes to the
|
|
||||||
* hashtable here because we mark all watchpoints as part of root marking in
|
|
||||||
* markAll().
|
|
||||||
*/
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WatchpointMap::unwatch(JSObject* obj, jsid id,
|
|
||||||
JSWatchPointHandler* handlerp, JSObject** closurep)
|
|
||||||
{
|
|
||||||
if (Map::Ptr p = map.lookup(WatchKey(obj, id))) {
|
|
||||||
if (handlerp)
|
|
||||||
*handlerp = p->value().handler;
|
|
||||||
if (closurep) {
|
|
||||||
// Read barrier to prevent an incorrectly gray closure from escaping the
|
|
||||||
// watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp
|
|
||||||
JS::ExposeObjectToActiveJS(p->value().closure);
|
|
||||||
*closurep = p->value().closure;
|
|
||||||
}
|
|
||||||
map.remove(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WatchpointMap::unwatchObject(JSObject* obj)
|
|
||||||
{
|
|
||||||
for (Map::Enum e(map); !e.empty(); e.popFront()) {
|
|
||||||
Map::Entry& entry = e.front();
|
|
||||||
if (entry.key().object == obj)
|
|
||||||
e.removeFront();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WatchpointMap::clear()
|
|
||||||
{
|
|
||||||
map.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
WatchpointMap::triggerWatchpoint(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
|
|
||||||
{
|
|
||||||
Map::Ptr p = map.lookup(WatchKey(obj, id));
|
|
||||||
if (!p || p->value().held)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
AutoEntryHolder holder(cx, map, p);
|
|
||||||
|
|
||||||
/* Copy the entry, since GC would invalidate p. */
|
|
||||||
JSWatchPointHandler handler = p->value().handler;
|
|
||||||
RootedObject closure(cx, p->value().closure);
|
|
||||||
|
|
||||||
/* Determine the property's old value. */
|
|
||||||
Value old;
|
|
||||||
old.setUndefined();
|
|
||||||
if (obj->isNative()) {
|
|
||||||
NativeObject* nobj = &obj->as<NativeObject>();
|
|
||||||
if (Shape* shape = nobj->lookup(cx, id)) {
|
|
||||||
if (shape->hasSlot())
|
|
||||||
old = nobj->getSlot(shape->slot());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read barrier to prevent an incorrectly gray closure from escaping the
|
|
||||||
// watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp
|
|
||||||
JS::ExposeObjectToActiveJS(closure);
|
|
||||||
|
|
||||||
/* Call the handler. */
|
|
||||||
return handler(cx, obj, id, old, vp.address(), closure);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
WatchpointMap::markIteratively(JSTracer* trc)
|
|
||||||
{
|
|
||||||
bool marked = false;
|
|
||||||
for (Map::Enum e(map); !e.empty(); e.popFront()) {
|
|
||||||
Map::Entry& entry = e.front();
|
|
||||||
JSObject* priorKeyObj = entry.key().object;
|
|
||||||
jsid priorKeyId(entry.key().id.get());
|
|
||||||
bool objectIsLive =
|
|
||||||
IsMarked(trc->runtime(), const_cast<PreBarrieredObject*>(&entry.key().object));
|
|
||||||
if (objectIsLive || entry.value().held) {
|
|
||||||
if (!objectIsLive) {
|
|
||||||
TraceEdge(trc, const_cast<PreBarrieredObject*>(&entry.key().object),
|
|
||||||
"held Watchpoint object");
|
|
||||||
marked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(JSID_IS_STRING(priorKeyId) ||
|
|
||||||
JSID_IS_INT(priorKeyId) ||
|
|
||||||
JSID_IS_SYMBOL(priorKeyId));
|
|
||||||
TraceEdge(trc, const_cast<PreBarrieredId*>(&entry.key().id), "WatchKey::id");
|
|
||||||
|
|
||||||
if (entry.value().closure && !IsMarked(trc->runtime(), &entry.value().closure)) {
|
|
||||||
TraceEdge(trc, &entry.value().closure, "Watchpoint::closure");
|
|
||||||
marked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We will sweep this entry in sweepAll if !objectIsLive. */
|
|
||||||
if (priorKeyObj != entry.key().object || priorKeyId != entry.key().id)
|
|
||||||
e.rekeyFront(WatchKey(entry.key().object, entry.key().id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return marked;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WatchpointMap::markAll(JSTracer* trc)
|
|
||||||
{
|
|
||||||
for (Map::Enum e(map); !e.empty(); e.popFront()) {
|
|
||||||
Map::Entry& entry = e.front();
|
|
||||||
JSObject* object = entry.key().object;
|
|
||||||
jsid id = entry.key().id;
|
|
||||||
JSObject* priorObject = object;
|
|
||||||
jsid priorId = id;
|
|
||||||
MOZ_ASSERT(JSID_IS_STRING(priorId) || JSID_IS_INT(priorId) || JSID_IS_SYMBOL(priorId));
|
|
||||||
|
|
||||||
TraceManuallyBarrieredEdge(trc, &object, "held Watchpoint object");
|
|
||||||
TraceManuallyBarrieredEdge(trc, &id, "WatchKey::id");
|
|
||||||
TraceEdge(trc, &entry.value().closure, "Watchpoint::closure");
|
|
||||||
|
|
||||||
if (priorObject != object || priorId != id)
|
|
||||||
e.rekeyFront(WatchKey(object, id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WatchpointMap::sweepAll(JSRuntime* rt)
|
|
||||||
{
|
|
||||||
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
|
|
||||||
if (WatchpointMap* wpmap = c->watchpointMap)
|
|
||||||
wpmap->sweep();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WatchpointMap::sweep()
|
|
||||||
{
|
|
||||||
for (Map::Enum e(map); !e.empty(); e.popFront()) {
|
|
||||||
Map::Entry& entry = e.front();
|
|
||||||
JSObject* obj(entry.key().object);
|
|
||||||
if (IsAboutToBeFinalizedUnbarriered(&obj)) {
|
|
||||||
MOZ_ASSERT(!entry.value().held);
|
|
||||||
e.removeFront();
|
|
||||||
} else if (obj != entry.key().object) {
|
|
||||||
e.rekeyFront(WatchKey(obj, entry.key().id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WatchpointMap::traceAll(WeakMapTracer* trc)
|
|
||||||
{
|
|
||||||
JSRuntime* rt = trc->context;
|
|
||||||
for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) {
|
|
||||||
if (WatchpointMap* wpmap = comp->watchpointMap)
|
|
||||||
wpmap->trace(trc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WatchpointMap::trace(WeakMapTracer* trc)
|
|
||||||
{
|
|
||||||
for (Map::Range r = map.all(); !r.empty(); r.popFront()) {
|
|
||||||
Map::Entry& entry = r.front();
|
|
||||||
trc->trace(nullptr,
|
|
||||||
JS::GCCellPtr(entry.key().object.get()),
|
|
||||||
JS::GCCellPtr(entry.value().closure.get()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
||||||
* 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/. */
|
|
||||||
|
|
||||||
#ifndef jswatchpoint_h
|
|
||||||
#define jswatchpoint_h
|
|
||||||
|
|
||||||
#include "jsalloc.h"
|
|
||||||
|
|
||||||
#include "gc/Barrier.h"
|
|
||||||
#include "js/HashTable.h"
|
|
||||||
|
|
||||||
namespace js {
|
|
||||||
|
|
||||||
struct WeakMapTracer;
|
|
||||||
|
|
||||||
struct WatchKey {
|
|
||||||
WatchKey() {}
|
|
||||||
WatchKey(JSObject* obj, jsid id) : object(obj), id(id) {}
|
|
||||||
WatchKey(const WatchKey& key) : object(key.object.get()), id(key.id.get()) {}
|
|
||||||
|
|
||||||
// These are traced unconditionally during minor GC, so do not require
|
|
||||||
// post-barriers.
|
|
||||||
PreBarrieredObject object;
|
|
||||||
PreBarrieredId id;
|
|
||||||
|
|
||||||
bool operator!=(const WatchKey& other) const {
|
|
||||||
return object != other.object || id != other.id;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef bool
|
|
||||||
(* JSWatchPointHandler)(JSContext* cx, JSObject* obj, jsid id, const JS::Value& old,
|
|
||||||
JS::Value* newp, void* closure);
|
|
||||||
|
|
||||||
struct Watchpoint {
|
|
||||||
JSWatchPointHandler handler;
|
|
||||||
PreBarrieredObject closure; /* This is always marked in minor GCs and so doesn't require a postbarrier. */
|
|
||||||
bool held; /* true if currently running handler */
|
|
||||||
Watchpoint(JSWatchPointHandler handler, JSObject* closure, bool held)
|
|
||||||
: handler(handler), closure(closure), held(held) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WatchKeyHasher
|
|
||||||
{
|
|
||||||
typedef WatchKey Lookup;
|
|
||||||
static inline js::HashNumber hash(const Lookup& key);
|
|
||||||
|
|
||||||
static bool match(const WatchKey& k, const Lookup& l) {
|
|
||||||
return MovableCellHasher<PreBarrieredObject>::match(k.object, l.object) &&
|
|
||||||
DefaultHasher<PreBarrieredId>::match(k.id, l.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rekey(WatchKey& k, const WatchKey& newKey) {
|
|
||||||
k.object.unsafeSet(newKey.object);
|
|
||||||
k.id.unsafeSet(newKey.id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class WatchpointMap {
|
|
||||||
public:
|
|
||||||
typedef HashMap<WatchKey, Watchpoint, WatchKeyHasher, SystemAllocPolicy> Map;
|
|
||||||
|
|
||||||
bool init();
|
|
||||||
bool watch(JSContext* cx, HandleObject obj, HandleId id,
|
|
||||||
JSWatchPointHandler handler, HandleObject closure);
|
|
||||||
void unwatch(JSObject* obj, jsid id,
|
|
||||||
JSWatchPointHandler* handlerp, JSObject** closurep);
|
|
||||||
void unwatchObject(JSObject* obj);
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
bool triggerWatchpoint(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp);
|
|
||||||
|
|
||||||
bool markIteratively(JSTracer* trc);
|
|
||||||
void markAll(JSTracer* trc);
|
|
||||||
static void sweepAll(JSRuntime* rt);
|
|
||||||
void sweep();
|
|
||||||
|
|
||||||
static void traceAll(WeakMapTracer* trc);
|
|
||||||
void trace(WeakMapTracer* trc);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Map map;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace js
|
|
||||||
|
|
||||||
#endif /* jswatchpoint_h */
|
|
|
@ -315,13 +315,6 @@ class JS_FRIEND_API(SecurityWrapper) : public Base
|
||||||
virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override;
|
virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override;
|
||||||
virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
|
virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
|
||||||
|
|
||||||
// Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
|
|
||||||
// against.
|
|
||||||
|
|
||||||
virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
|
|
||||||
JS::HandleObject callable) const override;
|
|
||||||
virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const override;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allow our subclasses to select the superclass behavior they want without
|
* Allow our subclasses to select the superclass behavior they want without
|
||||||
* needing to specify an exact superclass.
|
* needing to specify an exact superclass.
|
||||||
|
|
|
@ -291,7 +291,6 @@ UNIFIED_SOURCES += [
|
||||||
'jspropertytree.cpp',
|
'jspropertytree.cpp',
|
||||||
'jsscript.cpp',
|
'jsscript.cpp',
|
||||||
'jsstr.cpp',
|
'jsstr.cpp',
|
||||||
'jswatchpoint.cpp',
|
|
||||||
'jsweakmap.cpp',
|
'jsweakmap.cpp',
|
||||||
'perf/jsperf.cpp',
|
'perf/jsperf.cpp',
|
||||||
'proxy/BaseProxyHandler.cpp',
|
'proxy/BaseProxyHandler.cpp',
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue