summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2019-10-27 02:51:11 +0200
committerwolfbeast <mcwerewolf@wolfbeast.com>2019-10-27 02:51:11 +0200
commita06015f9f6244f4bdfd2b4a168ac78ca946c7848 (patch)
treedc262274ecda4799835232951bdb160b9a7b7d0e
parent17780612394da6602b5aa42d7105c2cc6c9b0d14 (diff)
downloadaura-central-a06015f9f6244f4bdfd2b4a168ac78ca946c7848.tar.gz
Issue mcp-graveyard/UXP%1257 - Part 2: Remove watch/unwatch and JS watchpoint class.
-rw-r--r--js/src/builtin/Object.cpp95
-rw-r--r--js/src/gc/Marking.cpp7
-rw-r--r--js/src/gc/RootMarking.cpp1
-rw-r--r--js/src/jit/BaselineIC.cpp6
-rw-r--r--js/src/jit/IonCaches.cpp5
-rw-r--r--js/src/js.msg2
-rw-r--r--js/src/jsapi.cpp1
-rw-r--r--js/src/jscntxt.cpp1
-rw-r--r--js/src/jscompartment.cpp12
-rw-r--r--js/src/jscompartment.h3
-rw-r--r--js/src/jsfriendapi.cpp2
-rw-r--r--js/src/jsfriendapi.h24
-rw-r--r--js/src/jsgc.cpp14
-rw-r--r--js/src/jsobj.cpp66
-rw-r--r--js/src/jsobj.h20
-rw-r--r--js/src/jsobjinlines.h6
-rw-r--r--js/src/jsversion.h1
-rw-r--r--js/src/jswatchpoint.cpp246
-rw-r--r--js/src/jswatchpoint.h90
-rw-r--r--js/src/moz.build1
-rw-r--r--js/src/vm/NativeObject-inl.h8
-rw-r--r--js/src/vm/NativeObject.cpp14
-rw-r--r--js/src/vm/Runtime.cpp1
-rw-r--r--js/src/vm/Shape.h2
-rw-r--r--js/src/vm/TypeInference.cpp114
25 files changed, 65 insertions, 677 deletions
diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp
index 56c77f304..bfcc8d20e 100644
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -568,97 +568,6 @@ obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
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. */
bool
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_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 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_isPrototypeOf_str, obj_isPrototypeOf, 1,0),
JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0),
diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
index da3ef7d0d..262fc8cbc 100644
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2846,10 +2846,9 @@ struct UnmarkGrayTracer : public JS::CallbackTracer
*
* 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
- * to its value, and from an object being watched by a watchpoint to the
- * watchpoint's closure. These "implicit edges" are represented in some other
- * container object, such as the weakmap or the watchpoint itself. In these
- * cases, calling unmark gray on an object won't find all of its children.
+ * to its value. These "implicit edges" are represented in some other
+ * container object, such as the weakmap itself. In these cases, calling unmark
+ * gray on an object won't find all of its children.
*
* Handling these implicit edges has two parts:
* - A special pass enumerating all of the containers that know about the
diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp
index f5969bc1f..7d665e8eb 100644
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -14,7 +14,6 @@
#include "jsgc.h"
#include "jsprf.h"
#include "jstypes.h"
-#include "jswatchpoint.h"
#include "builtin/MapObject.h"
#include "frontend/BytecodeCompiler.h"
diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp
index a001357f8..9530f65fa 100644
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -4053,9 +4053,6 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
{
MOZ_ASSERT(!*attached);
- if (obj->watched())
- return true;
-
RootedShape shape(cx);
RootedObject holder(cx);
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
@@ -4151,9 +4148,6 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc,
MOZ_ASSERT(!*attached);
MOZ_ASSERT(!*isTemporarilyUnoptimizable);
- if (obj->watched())
- return true;
-
RootedShape shape(cx);
RootedObject holder(cx);
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp
index 48e0792bb..fb4291188 100644
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -3232,7 +3232,7 @@ SetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript*
MOZ_ASSERT(!*emitted);
MOZ_ASSERT(!*tryNativeAddSlot);
- if (!canAttachStub() || obj->watched())
+ if (!canAttachStub())
return true;
// Fail cache emission if the object is frozen
@@ -3897,9 +3897,6 @@ IsDenseElementSetInlineable(JSObject* obj, const Value& idval, const ConstantOrR
if (!obj->is<ArrayObject>())
return false;
- if (obj->watched())
- return false;
-
if (!idval.isInt32())
return false;
diff --git a/js/src/js.msg b/js/src/js.msg
index f57b36a90..1612c831d 100644
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -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_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_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_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")
@@ -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_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_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_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")
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index cad0840e0..f9a0c6a6b 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -39,7 +39,6 @@
#include "jsstr.h"
#include "jstypes.h"
#include "jsutil.h"
-#include "jswatchpoint.h"
#include "jsweakmap.h"
#include "jswrapper.h"
diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp
index e505a4b34..23b9d27ae 100644
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -37,7 +37,6 @@
#include "jsscript.h"
#include "jsstr.h"
#include "jstypes.h"
-#include "jswatchpoint.h"
#include "gc/Marking.h"
#include "jit/Ion.h"
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index d0caeb558..8ba186b08 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -13,7 +13,6 @@
#include "jsfriendapi.h"
#include "jsgc.h"
#include "jsiter.h"
-#include "jswatchpoint.h"
#include "jswrapper.h"
#include "gc/Marking.h"
@@ -76,7 +75,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
gcIncomingGrayPointers(nullptr),
debugModeBits(0),
randomKeyGenerator_(runtime_->forkRandomKeyGenerator()),
- watchpointMap(nullptr),
scriptCountsMap(nullptr),
debugScriptMap(nullptr),
debugEnvs(nullptr),
@@ -103,7 +101,6 @@ JSCompartment::~JSCompartment()
rt->lcovOutput.writeLCovResult(lcovOutput);
js_delete(jitCompartment_);
- js_delete(watchpointMap);
js_delete(scriptCountsMap);
js_delete(debugScriptMap);
js_delete(debugEnvs);
@@ -662,12 +659,6 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t
if (traceOrMark == js::gc::GCRuntime::MarkRuntime && !zone()->isCollecting())
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 */
if (debugEnvs)
debugEnvs->mark(trc);
@@ -712,9 +703,6 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t
void
JSCompartment::finishRoots()
{
- if (watchpointMap)
- watchpointMap->clear();
-
if (debugEnvs)
debugEnvs->finish();
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index 83c15da3b..05ff40b43 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -282,7 +282,6 @@ class MOZ_RAII AutoSetNewObjectMetadata : private JS::CustomAutoRooter
namespace js {
class DebugEnvironments;
class ObjectWeakMap;
-class WatchpointMap;
class WeakMapBase;
} // namespace js
@@ -811,8 +810,6 @@ struct JSCompartment
void sweepBreakpoints(js::FreeOp* fop);
public:
- js::WatchpointMap* watchpointMap;
-
js::ScriptCountsMap* scriptCountsMap;
js::DebugScriptMap* debugScriptMap;
diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp
index f7622cb44..bdb3c0a4d 100644
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -15,7 +15,6 @@
#include "jsgc.h"
#include "jsobj.h"
#include "jsprf.h"
-#include "jswatchpoint.h"
#include "jsweakmap.h"
#include "jswrapper.h"
@@ -579,7 +578,6 @@ void
js::TraceWeakMaps(WeakMapTracer* trc)
{
WeakMapBase::traceAllMappings(trc);
- WatchpointMap::traceAll(trc);
}
extern JS_FRIEND_API(bool)
diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
index 351667fb3..491215456 100644
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -2110,30 +2110,6 @@ JS_FRIEND_API(void*)
JS_GetDataViewData(JSObject* obj, const JS::AutoCheckCannotGC&);
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 {
enum class InlinableNative : uint16_t;
diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp
index b2ee8d67b..5a9d732b6 100644
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -207,7 +207,6 @@
#include "jsscript.h"
#include "jstypes.h"
#include "jsutil.h"
-#include "jswatchpoint.h"
#include "jsweakmap.h"
#ifdef XP_WIN
# include "jswin.h"
@@ -2392,11 +2391,6 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAccess
Debugger::markIncomingCrossCompartmentEdges(&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
// current set.
@@ -2405,7 +2399,6 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAccess
}
// Sweep everything to fix up weak pointers
- WatchpointMap::sweepAll(rt);
Debugger::sweepAll(rt->defaultFreeOp());
jit::JitRuntime::SweepJitcodeGlobalTable(rt);
rt->gc.sweepZoneAfterCompacting(zone);
@@ -3850,10 +3843,6 @@ GCRuntime::markWeakReferences(gcstats::Phase phase)
for (ZoneIterT zone(rt); !zone.done(); zone.next())
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 |= jit::JitRuntime::MarkJitcodeGlobalTableIteratively(&marker);
@@ -4625,9 +4614,6 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock)
// Bug 1071218: the following two methods have not yet been
// 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.
Debugger::sweepAll(&fop);
diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
index ee66addc9..ef1291079 100644
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -33,7 +33,6 @@
#include "jsstr.h"
#include "jstypes.h"
#include "jsutil.h"
-#include "jswatchpoint.h"
#include "jswin.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,
HandleValue receiver, ObjectOpResult& result)
{
- RootedValue value(cx, v);
- 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);
+ return obj->getOpsSetProperty()(cx, obj, id, v, receiver, result);
}
/* static */ bool
@@ -2795,62 +2788,6 @@ js::GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
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 (!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)
-{
- return UnwatchGuts(cx, obj, id);
-}
-
const char*
js::GetObjectClassName(JSContext* cx, HandleObject obj)
{
@@ -3410,7 +3347,6 @@ JSObject::dump(FILE* fp) const
if (obj->isBoundFunction()) fprintf(fp, " bound_function");
if (obj->isQualifiedVarObj()) fprintf(fp, " varobj");
if (obj->isUnqualifiedVarObj()) fprintf(fp, " unqualified_varobj");
- if (obj->watched()) fprintf(fp, " watched");
if (obj->isIteratedSingleton()) fprintf(fp, " iterated_singleton");
if (obj->isNewGroupUnknown()) fprintf(fp, " new_type_unknown");
if (obj->hasUncacheableProto()) fprintf(fp, " has_uncacheable_proto");
diff --git a/js/src/jsobj.h b/js/src/jsobj.h
index 8a41d155e..01845d7e6 100644
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -219,11 +219,6 @@ class JSObject : public js::gc::Cell
inline bool isBoundFunction() 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
// declarations (i.e., those defined with "var") are kept.
//
@@ -1030,21 +1025,6 @@ extern bool
DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
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]) */
extern bool
ToPrimitiveSlow(JSContext* cx, JSType hint, MutableHandleValue vp);
diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h
index c132ee6b2..98e740142 100644
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -464,12 +464,6 @@ JSObject::isBoundFunction() const
}
inline bool
-JSObject::watched() const
-{
- return hasAllFlags(js::BaseShape::WATCHED);
-}
-
-inline bool
JSObject::isDelegate() const
{
return hasAllFlags(js::BaseShape::DELEGATE);
diff --git a/js/src/jsversion.h b/js/src/jsversion.h
index 8bdfe47b6..cf4c6e73a 100644
--- a/js/src/jsversion.h
+++ b/js/src/jsversion.h
@@ -12,7 +12,6 @@
*/
#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_WATCHPOINT 1 /* has o.watch and o.unwatch */
#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */
#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */
#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */
diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp
deleted file mode 100644
index 34479a990..000000000
--- a/js/src/jswatchpoint.cpp
+++ /dev/null
@@ -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()));
- }
-}
diff --git a/js/src/jswatchpoint.h b/js/src/jswatchpoint.h
deleted file mode 100644
index bba6c38ce..000000000
--- a/js/src/jswatchpoint.h
+++ /dev/null
@@ -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 */
diff --git a/js/src/moz.build b/js/src/moz.build
index a0f074d1c..5ce0dfd98 100644
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -291,7 +291,6 @@ UNIFIED_SOURCES += [
'jspropertytree.cpp',
'jsscript.cpp',
'jsstr.cpp',
- 'jswatchpoint.cpp',
'jsweakmap.cpp',
'perf/jsperf.cpp',
'proxy/BaseProxyHandler.cpp',
diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h
index e55e3db04..030d92c12 100644
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -158,11 +158,11 @@ NativeObject::extendDenseElements(ExclusiveContext* cx,
MOZ_ASSERT(!denseElementsAreFrozen());
/*
- * Don't grow elements for non-extensible objects or watched objects. Dense
- * elements can be added/written with no extensible or watchpoint checks as
- * long as there is capacity for them.
+ * Don't grow elements for non-extensible objects. Dense elements can be
+ * added/written with no extensible checks as long as there is capacity
+ * for them.
*/
- if (!nonProxyIsExtensible() || watched()) {
+ if (!nonProxyIsExtensible()) {
MOZ_ASSERT(getDenseCapacity() == 0);
return DenseElementResult::Incomplete;
}
diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
index da0f59fe2..d801fad06 100644
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -9,8 +9,6 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
-#include "jswatchpoint.h"
-
#include "gc/Marking.h"
#include "js/Value.h"
#include "vm/Debugger.h"
@@ -602,7 +600,7 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO
return DenseElementResult::Incomplete;
/* Watch for conditions under which an object's elements cannot be dense. */
- if (!obj->nonProxyIsExtensible() || obj->watched())
+ if (!obj->nonProxyIsExtensible())
return DenseElementResult::Incomplete;
/*
@@ -2410,17 +2408,9 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa
}
bool
-js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue value,
+js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
HandleValue receiver, QualifiedBool qualified, ObjectOpResult& result)
{
- // Fire watchpoints, if any.
- RootedValue v(cx, value);
- if (MOZ_UNLIKELY(obj->watched())) {
- WatchpointMap* wpmap = cx->compartment()->watchpointMap;
- if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &v))
- return false;
- }
-
// Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal
// method for ordinary objects. We substitute our own names for these names
// used in the spec: O -> pobj, P -> id, ownDesc -> shape.
diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
index 5fc8e0e17..284a4f3d7 100644
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -34,7 +34,6 @@
#include "jsnativestack.h"
#include "jsobj.h"
#include "jsscript.h"
-#include "jswatchpoint.h"
#include "jswin.h"
#include "jswrapper.h"
diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h
index fd6d843e0..85bc044a5 100644
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -387,7 +387,7 @@ class BaseShape : public gc::TenuredCell
INDEXED = 0x20,
/* (0x40 is unused) */
HAD_ELEMENTS_ACCESS = 0x80,
- WATCHED = 0x100,
+ /* (0x100 is unused) */
ITERATED_SINGLETON = 0x200,
NEW_GROUP_UNKNOWN = 0x400,
UNCACHEABLE_PROTO = 0x800,
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index 88327b47e..2b1fa0e3b 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -2670,14 +2670,6 @@ ObjectGroup::updateNewPropertyTypes(ExclusiveContext* cx, JSObject* objArg, jsid
if (shape)
UpdatePropertyType(cx, types, obj, shape, false);
}
-
- if (obj->watched()) {
- /*
- * Mark the property as non-data, to inhibit optimizations on it
- * and avoid bypassing the watchpoint handler.
- */
- types->setNonDataProperty(cx);
- }
}
void
@@ -3622,42 +3614,42 @@ struct DestroyTypeNewScript
} // namespace
-bool DPAConstraintInfo::finishConstraints(JSContext* cx, ObjectGroup* group) {
- for (const ProtoConstraint& constraint : protoConstraints_) {
- ObjectGroup* protoGroup = constraint.proto->group();
-
- // Note: we rely on the group's type information being unchanged since
- // AddClearDefiniteGetterSetterForPrototypeChain.
-
- bool unknownProperties = protoGroup->unknownProperties();
- MOZ_RELEASE_ASSERT(!unknownProperties);
-
- HeapTypeSet* protoTypes =
- protoGroup->getProperty(cx, constraint.proto, constraint.id);
- MOZ_RELEASE_ASSERT(protoTypes);
-
- MOZ_ASSERT(!protoTypes->nonDataProperty());
- MOZ_ASSERT(!protoTypes->nonWritableProperty());
-
- if (!protoTypes->addConstraint(
- cx,
- cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(
- group))) {
- ReportOutOfMemory(cx);
- return false;
- }
- }
-
- for (const InliningConstraint& constraint : inliningConstraints_) {
- if (!AddClearDefiniteFunctionUsesInScript(cx, group, constraint.caller,
- constraint.callee)) {
- ReportOutOfMemory(cx);
- return false;
- }
- }
-
- return true;
-}
+bool DPAConstraintInfo::finishConstraints(JSContext* cx, ObjectGroup* group) {
+ for (const ProtoConstraint& constraint : protoConstraints_) {
+ ObjectGroup* protoGroup = constraint.proto->group();
+
+ // Note: we rely on the group's type information being unchanged since
+ // AddClearDefiniteGetterSetterForPrototypeChain.
+
+ bool unknownProperties = protoGroup->unknownProperties();
+ MOZ_RELEASE_ASSERT(!unknownProperties);
+
+ HeapTypeSet* protoTypes =
+ protoGroup->getProperty(cx, constraint.proto, constraint.id);
+ MOZ_RELEASE_ASSERT(protoTypes);
+
+ MOZ_ASSERT(!protoTypes->nonDataProperty());
+ MOZ_ASSERT(!protoTypes->nonWritableProperty());
+
+ if (!protoTypes->addConstraint(
+ cx,
+ cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(
+ group))) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ for (const InliningConstraint& constraint : inliningConstraints_) {
+ if (!AddClearDefiniteFunctionUsesInScript(cx, group, constraint.caller,
+ constraint.callee)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ return true;
+}
bool
TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force)
@@ -3826,13 +3818,13 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
// The definite properties analysis found exactly the properties that
// are held in common by the preliminary objects. No further analysis
// is needed.
-
- if (!constraintInfo.finishConstraints(cx, group)) {
- return false;
- }
- if (!group->newScript()) {
- return true;
- }
+
+ if (!constraintInfo.finishConstraints(cx, group)) {
+ return false;
+ }
+ if (!group->newScript()) {
+ return true;
+ }
group->addDefiniteProperties(cx, templateObject()->lastProperty());
@@ -3854,16 +3846,16 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
initialFlags);
if (!initialGroup)
return false;
-
- // Add the constraints. Use the initialGroup as group referenced by the
- // constraints because that's the group that will have the TypeNewScript
- // associated with it. See the detachNewScript and setNewScript calls below.
- if (!constraintInfo.finishConstraints(cx, initialGroup)) {
- return false;
- }
- if (!group->newScript()) {
- return true;
- }
+
+ // Add the constraints. Use the initialGroup as group referenced by the
+ // constraints because that's the group that will have the TypeNewScript
+ // associated with it. See the detachNewScript and setNewScript calls below.
+ if (!constraintInfo.finishConstraints(cx, initialGroup)) {
+ return false;
+ }
+ if (!group->newScript()) {
+ return true;
+ }
initialGroup->addDefiniteProperties(cx, templateObject()->lastProperty());
group->addDefiniteProperties(cx, prefixShape);