diff options
-rw-r--r-- | js/src/builtin/Object.cpp | 95 | ||||
-rw-r--r-- | js/src/gc/Marking.cpp | 7 | ||||
-rw-r--r-- | js/src/gc/RootMarking.cpp | 1 | ||||
-rw-r--r-- | js/src/jit/BaselineIC.cpp | 6 | ||||
-rw-r--r-- | js/src/jit/IonCaches.cpp | 5 | ||||
-rw-r--r-- | js/src/js.msg | 2 | ||||
-rw-r--r-- | js/src/jsapi.cpp | 1 | ||||
-rw-r--r-- | js/src/jscntxt.cpp | 1 | ||||
-rw-r--r-- | js/src/jscompartment.cpp | 12 | ||||
-rw-r--r-- | js/src/jscompartment.h | 3 | ||||
-rw-r--r-- | js/src/jsfriendapi.cpp | 2 | ||||
-rw-r--r-- | js/src/jsfriendapi.h | 24 | ||||
-rw-r--r-- | js/src/jsgc.cpp | 14 | ||||
-rw-r--r-- | js/src/jsobj.cpp | 66 | ||||
-rw-r--r-- | js/src/jsobj.h | 20 | ||||
-rw-r--r-- | js/src/jsobjinlines.h | 6 | ||||
-rw-r--r-- | js/src/jsversion.h | 1 | ||||
-rw-r--r-- | js/src/jswatchpoint.cpp | 246 | ||||
-rw-r--r-- | js/src/jswatchpoint.h | 90 | ||||
-rw-r--r-- | js/src/moz.build | 1 | ||||
-rw-r--r-- | js/src/vm/NativeObject-inl.h | 8 | ||||
-rw-r--r-- | js/src/vm/NativeObject.cpp | 14 | ||||
-rw-r--r-- | js/src/vm/Runtime.cpp | 1 | ||||
-rw-r--r-- | js/src/vm/Shape.h | 2 | ||||
-rw-r--r-- | js/src/vm/TypeInference.cpp | 114 |
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); |