summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/public/GCAPI.h8
-rw-r--r--js/src/frontend/Parser.cpp13
-rw-r--r--js/src/frontend/Parser.h2
-rw-r--r--js/src/gc/Nursery.cpp8
-rw-r--r--js/src/gc/Statistics.cpp219
-rw-r--r--js/src/jsapi.h13
-rw-r--r--js/src/jscompartment.cpp37
-rw-r--r--js/src/jscompartment.h31
-rw-r--r--js/src/jsexn.cpp65
-rw-r--r--js/src/jsfriendapi.cpp11
-rw-r--r--js/src/jsfriendapi.h43
-rw-r--r--js/src/jsfun.cpp10
-rw-r--r--js/src/jsgc.cpp11
-rw-r--r--js/src/jsstr.cpp5
-rw-r--r--js/src/jswrapper.h2
-rw-r--r--js/src/proxy/OpaqueCrossCompartmentWrapper.cpp8
-rw-r--r--js/src/proxy/ScriptedProxyHandler.cpp4
-rwxr-xr-xjs/src/tests/user.js1
-rw-r--r--js/src/vm/Interpreter.cpp14
-rw-r--r--js/src/vm/Interpreter.h3
-rw-r--r--js/src/vm/Runtime.cpp14
-rw-r--r--js/src/vm/Runtime.h10
-rw-r--r--js/src/vm/SelfHosting.cpp18
-rw-r--r--js/src/vm/Stopwatch.cpp48
-rw-r--r--js/src/vm/Stopwatch.h30
-rw-r--r--js/src/wasm/WasmBinaryConstants.h9
-rw-r--r--js/src/wasm/WasmModule.cpp3
-rw-r--r--js/xpconnect/loader/mozJSSubScriptLoader.cpp1
-rw-r--r--js/xpconnect/src/Sandbox.cpp1
-rw-r--r--js/xpconnect/src/XPCJSContext.cpp21
-rw-r--r--js/xpconnect/src/nsScriptErrorWithStack.cpp1
-rw-r--r--js/xpconnect/src/xpcprivate.h3
-rw-r--r--js/xpconnect/wrappers/WaiveXrayWrapper.cpp31
-rw-r--r--js/xpconnect/wrappers/WaiveXrayWrapper.h2
-rw-r--r--js/xpconnect/wrappers/XrayWrapper.cpp14
-rw-r--r--js/xpconnect/wrappers/XrayWrapper.h2
36 files changed, 175 insertions, 541 deletions
diff --git a/js/public/GCAPI.h b/js/public/GCAPI.h
index 7a6675ca72..4ef2a8370a 100644
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -119,14 +119,6 @@ enum Reason {
#undef MAKE_REASON
NO_REASON,
NUM_REASONS,
-
- /*
- * For telemetry, we want to keep a fixed max bucket size over time so we
- * don't have to switch histograms. 100 is conservative; as of this writing
- * there are 52. But the cost of extra buckets seems to be low while the
- * cost of switching histograms is high.
- */
- NUM_TELEMETRY_REASONS = 100
};
/**
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 7bfab87a34..209265a584 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -3463,7 +3463,6 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
if (kind != Arrow) {
#if JS_HAS_EXPR_CLOSURES
- addTelemetry(JSCompartment::DeprecatedExpressionClosure);
if (!warnOnceAboutExprClosure())
return false;
#else
@@ -5545,7 +5544,6 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
if (matched) {
iflags = JSITER_FOREACH;
isForEach = true;
- addTelemetry(JSCompartment::DeprecatedForEach);
if (!warnOnceAboutForEach())
return null();
}
@@ -6077,7 +6075,6 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
}
pc->functionBox()->setGeneratorKind(LegacyGenerator);
- addTelemetry(JSCompartment::DeprecatedLegacyGenerator);
MOZ_FALLTHROUGH;
@@ -9589,16 +9586,6 @@ Parser<ParseHandler>::exprInParens(InHandling inHandling, YieldHandling yieldHan
}
template <typename ParseHandler>
-void
-Parser<ParseHandler>::addTelemetry(JSCompartment::DeprecatedLanguageExtension e)
-{
- JSContext* cx = context->maybeJSContext();
- if (!cx)
- return;
- cx->compartment()->addTelemetry(getFilename(), e);
-}
-
-template <typename ParseHandler>
bool
Parser<ParseHandler>::warnOnceAboutExprClosure()
{
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index b58b021cd7..12642fad82 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1420,8 +1420,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool asmJS(Node list);
- void addTelemetry(JSCompartment::DeprecatedLanguageExtension e);
-
bool warnOnceAboutExprClosure();
bool warnOnceAboutForEach();
};
diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp
index 55ca5a059d..ea4350fb86 100644
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -530,7 +530,6 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason)
// the nursery is full, look for object groups that are getting promoted
// excessively and try to pretenure them.
maybeStartProfile(ProfileKey::Pretenure);
- uint32_t pretenureCount = 0;
if (promotionRate > 0.8 || reason == JS::gcreason::FULL_STORE_BUFFER) {
JSContext* cx = rt->contextFromMainThread();
for (auto& entry : tenureCounts.entries) {
@@ -539,7 +538,6 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason)
if (group->canPreTenure()) {
AutoCompartment ac(cx, group->compartment());
group->setShouldPreTenure(cx);
- pretenureCount++;
}
}
}
@@ -556,12 +554,6 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason)
minorGcCount_++;
int64_t totalTime = profileTimes_[ProfileKey::Total];
- rt->addTelemetry(JS_TELEMETRY_GC_MINOR_US, totalTime);
- rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON, reason);
- if (totalTime > 1000)
- rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON_LONG, reason);
- rt->addTelemetry(JS_TELEMETRY_GC_NURSERY_BYTES, sizeOfHeapCommitted());
- rt->addTelemetry(JS_TELEMETRY_GC_PRETENURE_COUNT, pretenureCount);
rt->gc.stats.endNurseryCollection(reason);
TraceMinorGCEnd();
diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp
index 19f9986dd2..8a9f4e1350 100644
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -34,13 +34,6 @@ using mozilla::MakeRange;
using mozilla::PodArrayZero;
using mozilla::PodZero;
-/*
- * If this fails, then you can either delete this assertion and allow all
- * larger-numbered reasons to pile up in the last telemetry bucket, or switch
- * to GC_REASON_3 and bump the max value.
- */
-JS_STATIC_ASSERT(JS::gcreason::NUM_TELEMETRY_REASONS >= JS::gcreason::NUM_REASONS);
-
const char*
js::gcstats::ExplainInvocationKind(JSGCInvocationKind gckind)
{
@@ -92,7 +85,6 @@ struct PhaseInfo
Phase index;
const char* name;
Phase parent;
- const uint8_t telemetryBucket;
};
// The zeroth entry in the timing arrays is used for phases that have a
@@ -134,78 +126,74 @@ struct DagChildEdge {
*/
static const PhaseInfo phases[] = {
- { PHASE_MUTATOR, "Mutator Running", PHASE_NO_PARENT, 0 },
- { PHASE_GC_BEGIN, "Begin Callback", PHASE_NO_PARENT, 1 },
- { PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread", PHASE_NO_PARENT, 2 },
- { PHASE_MARK_DISCARD_CODE, "Mark Discard Code", PHASE_NO_PARENT, 3 },
- { PHASE_RELAZIFY_FUNCTIONS, "Relazify Functions", PHASE_NO_PARENT, 4 },
- { PHASE_PURGE, "Purge", PHASE_NO_PARENT, 5 },
- { PHASE_MARK, "Mark", PHASE_NO_PARENT, 6 },
- { PHASE_UNMARK, "Unmark", PHASE_MARK, 7 },
+ { PHASE_MUTATOR, "Mutator Running", PHASE_NO_PARENT },
+ { PHASE_GC_BEGIN, "Begin Callback", PHASE_NO_PARENT },
+ { PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread", PHASE_NO_PARENT },
+ { PHASE_MARK_DISCARD_CODE, "Mark Discard Code", PHASE_NO_PARENT },
+ { PHASE_RELAZIFY_FUNCTIONS, "Relazify Functions", PHASE_NO_PARENT },
+ { PHASE_PURGE, "Purge", PHASE_NO_PARENT },
+ { PHASE_MARK, "Mark", PHASE_NO_PARENT },
+ { PHASE_UNMARK, "Unmark", PHASE_MARK },
/* PHASE_MARK_ROOTS */
- { PHASE_MARK_DELAYED, "Mark Delayed", PHASE_MARK, 8 },
- { PHASE_SWEEP, "Sweep", PHASE_NO_PARENT, 9 },
- { PHASE_SWEEP_MARK, "Mark During Sweeping", PHASE_SWEEP, 10 },
- { PHASE_SWEEP_MARK_TYPES, "Mark Types During Sweeping", PHASE_SWEEP_MARK, 11 },
- { PHASE_SWEEP_MARK_INCOMING_BLACK, "Mark Incoming Black Pointers", PHASE_SWEEP_MARK, 12 },
- { PHASE_SWEEP_MARK_WEAK, "Mark Weak", PHASE_SWEEP_MARK, 13 },
- { PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK, 14 },
- { PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK, 15 },
- { PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK, 16 },
- { PHASE_FINALIZE_START, "Finalize Start Callbacks", PHASE_SWEEP, 17 },
- { PHASE_WEAK_ZONEGROUP_CALLBACK, "Per-Slice Weak Callback", PHASE_FINALIZE_START, 57 },
- { PHASE_WEAK_COMPARTMENT_CALLBACK, "Per-Compartment Weak Callback", PHASE_FINALIZE_START, 58 },
- { PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP, 18 },
- { PHASE_SWEEP_SYMBOL_REGISTRY, "Sweep Symbol Registry", PHASE_SWEEP, 19 },
- { PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments", PHASE_SWEEP, 20 },
- { PHASE_SWEEP_DISCARD_CODE, "Sweep Discard Code", PHASE_SWEEP_COMPARTMENTS, 21 },
- { PHASE_SWEEP_INNER_VIEWS, "Sweep Inner Views", PHASE_SWEEP_COMPARTMENTS, 22 },
- { PHASE_SWEEP_CC_WRAPPER, "Sweep Cross Compartment Wrappers", PHASE_SWEEP_COMPARTMENTS, 23 },
- { PHASE_SWEEP_BASE_SHAPE, "Sweep Base Shapes", PHASE_SWEEP_COMPARTMENTS, 24 },
- { PHASE_SWEEP_INITIAL_SHAPE, "Sweep Initial Shapes", PHASE_SWEEP_COMPARTMENTS, 25 },
- { PHASE_SWEEP_TYPE_OBJECT, "Sweep Type Objects", PHASE_SWEEP_COMPARTMENTS, 26 },
- { PHASE_SWEEP_BREAKPOINT, "Sweep Breakpoints", PHASE_SWEEP_COMPARTMENTS, 27 },
- { PHASE_SWEEP_REGEXP, "Sweep Regexps", PHASE_SWEEP_COMPARTMENTS, 28 },
- { PHASE_SWEEP_MISC, "Sweep Miscellaneous", PHASE_SWEEP_COMPARTMENTS, 29 },
- { PHASE_SWEEP_TYPES, "Sweep type information", PHASE_SWEEP_COMPARTMENTS, 30 },
- { PHASE_SWEEP_TYPES_BEGIN, "Sweep type tables and compilations", PHASE_SWEEP_TYPES, 31 },
- { PHASE_SWEEP_TYPES_END, "Free type arena", PHASE_SWEEP_TYPES, 32 },
- { PHASE_SWEEP_OBJECT, "Sweep Object", PHASE_SWEEP, 33 },
- { PHASE_SWEEP_STRING, "Sweep String", PHASE_SWEEP, 34 },
- { PHASE_SWEEP_SCRIPT, "Sweep Script", PHASE_SWEEP, 35 },
- { PHASE_SWEEP_SCOPE, "Sweep Scope", PHASE_SWEEP, 59 },
- { PHASE_SWEEP_SHAPE, "Sweep Shape", PHASE_SWEEP, 36 },
- { PHASE_SWEEP_JITCODE, "Sweep JIT code", PHASE_SWEEP, 37 },
- { PHASE_FINALIZE_END, "Finalize End Callback", PHASE_SWEEP, 38 },
- { PHASE_DESTROY, "Deallocate", PHASE_SWEEP, 39 },
- { PHASE_COMPACT, "Compact", PHASE_NO_PARENT, 40 },
- { PHASE_COMPACT_MOVE, "Compact Move", PHASE_COMPACT, 41 },
- { PHASE_COMPACT_UPDATE, "Compact Update", PHASE_COMPACT, 42 },
+ { PHASE_MARK_DELAYED, "Mark Delayed", PHASE_MARK },
+ { PHASE_SWEEP, "Sweep", PHASE_NO_PARENT },
+ { PHASE_SWEEP_MARK, "Mark During Sweeping", PHASE_SWEEP },
+ { PHASE_SWEEP_MARK_TYPES, "Mark Types During Sweeping", PHASE_SWEEP_MARK },
+ { PHASE_SWEEP_MARK_INCOMING_BLACK, "Mark Incoming Black Pointers", PHASE_SWEEP_MARK },
+ { PHASE_SWEEP_MARK_WEAK, "Mark Weak", PHASE_SWEEP_MARK },
+ { PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK },
+ { PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK },
+ { PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK },
+ { PHASE_FINALIZE_START, "Finalize Start Callbacks", PHASE_SWEEP },
+ { PHASE_WEAK_ZONEGROUP_CALLBACK, "Per-Slice Weak Callback", PHASE_FINALIZE_START },
+ { PHASE_WEAK_COMPARTMENT_CALLBACK, "Per-Compartment Weak Callback", PHASE_FINALIZE_START },
+ { PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP },
+ { PHASE_SWEEP_SYMBOL_REGISTRY, "Sweep Symbol Registry", PHASE_SWEEP },
+ { PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments", PHASE_SWEEP },
+ { PHASE_SWEEP_DISCARD_CODE, "Sweep Discard Code", PHASE_SWEEP_COMPARTMENTS },
+ { PHASE_SWEEP_INNER_VIEWS, "Sweep Inner Views", PHASE_SWEEP_COMPARTMENTS },
+ { PHASE_SWEEP_CC_WRAPPER, "Sweep Cross Compartment Wrappers", PHASE_SWEEP_COMPARTMENTS },
+ { PHASE_SWEEP_BASE_SHAPE, "Sweep Base Shapes", PHASE_SWEEP_COMPARTMENTS },
+ { PHASE_SWEEP_INITIAL_SHAPE, "Sweep Initial Shapes", PHASE_SWEEP_COMPARTMENTS },
+ { PHASE_SWEEP_TYPE_OBJECT, "Sweep Type Objects", PHASE_SWEEP_COMPARTMENTS },
+ { PHASE_SWEEP_BREAKPOINT, "Sweep Breakpoints", PHASE_SWEEP_COMPARTMENTS },
+ { PHASE_SWEEP_REGEXP, "Sweep Regexps", PHASE_SWEEP_COMPARTMENTS },
+ { PHASE_SWEEP_MISC, "Sweep Miscellaneous", PHASE_SWEEP_COMPARTMENTS },
+ { PHASE_SWEEP_TYPES, "Sweep type information", PHASE_SWEEP_COMPARTMENTS },
+ { PHASE_SWEEP_TYPES_BEGIN, "Sweep type tables and compilations", PHASE_SWEEP_TYPES },
+ { PHASE_SWEEP_TYPES_END, "Free type arena", PHASE_SWEEP_TYPES },
+ { PHASE_SWEEP_OBJECT, "Sweep Object", PHASE_SWEEP },
+ { PHASE_SWEEP_STRING, "Sweep String", PHASE_SWEEP },
+ { PHASE_SWEEP_SCRIPT, "Sweep Script", PHASE_SWEEP },
+ { PHASE_SWEEP_SCOPE, "Sweep Scope", PHASE_SWEEP },
+ { PHASE_SWEEP_SHAPE, "Sweep Shape", PHASE_SWEEP },
+ { PHASE_SWEEP_JITCODE, "Sweep JIT code", PHASE_SWEEP },
+ { PHASE_FINALIZE_END, "Finalize End Callback", PHASE_SWEEP },
+ { PHASE_DESTROY, "Deallocate", PHASE_SWEEP },
+ { PHASE_COMPACT, "Compact", PHASE_NO_PARENT },
+ { PHASE_COMPACT_MOVE, "Compact Move", PHASE_COMPACT },
+ { PHASE_COMPACT_UPDATE, "Compact Update", PHASE_COMPACT },
/* PHASE_MARK_ROOTS */
- { PHASE_COMPACT_UPDATE_CELLS, "Compact Update Cells", PHASE_COMPACT_UPDATE, 43 },
- { PHASE_GC_END, "End Callback", PHASE_NO_PARENT, 44 },
- { PHASE_MINOR_GC, "All Minor GCs", PHASE_NO_PARENT, 45 },
+ { PHASE_COMPACT_UPDATE_CELLS, "Compact Update Cells", PHASE_COMPACT_UPDATE },
+ { PHASE_GC_END, "End Callback", PHASE_NO_PARENT },
+ { PHASE_MINOR_GC, "All Minor GCs", PHASE_NO_PARENT },
/* PHASE_MARK_ROOTS */
- { PHASE_EVICT_NURSERY, "Minor GCs to Evict Nursery", PHASE_NO_PARENT, 46 },
+ { PHASE_EVICT_NURSERY, "Minor GCs to Evict Nursery", PHASE_NO_PARENT },
/* PHASE_MARK_ROOTS */
- { PHASE_TRACE_HEAP, "Trace Heap", PHASE_NO_PARENT, 47 },
+ { PHASE_TRACE_HEAP, "Trace Heap", PHASE_NO_PARENT },
/* PHASE_MARK_ROOTS */
- { PHASE_BARRIER, "Barriers", PHASE_NO_PARENT, 55 },
- { PHASE_UNMARK_GRAY, "Unmark gray", PHASE_BARRIER, 56 },
- { PHASE_MARK_ROOTS, "Mark Roots", PHASE_MULTI_PARENTS, 48 },
- { PHASE_BUFFER_GRAY_ROOTS, "Buffer Gray Roots", PHASE_MARK_ROOTS, 49 },
- { PHASE_MARK_CCWS, "Mark Cross Compartment Wrappers", PHASE_MARK_ROOTS, 50 },
- { PHASE_MARK_STACK, "Mark C and JS stacks", PHASE_MARK_ROOTS, 51 },
- { PHASE_MARK_RUNTIME_DATA, "Mark Runtime-wide Data", PHASE_MARK_ROOTS, 52 },
- { PHASE_MARK_EMBEDDING, "Mark Embedding", PHASE_MARK_ROOTS, 53 },
- { PHASE_MARK_COMPARTMENTS, "Mark Compartments", PHASE_MARK_ROOTS, 54 },
- { PHASE_PURGE_SHAPE_TABLES, "Purge ShapeTables", PHASE_NO_PARENT, 60 },
-
- { PHASE_LIMIT, nullptr, PHASE_NO_PARENT, 60 }
-
- // Current number of telemetryBuckets is 60. If you insert new phases
- // somewhere, start at that number and count up. Do not change any existing
- // numbers.
+ { PHASE_BARRIER, "Barriers", PHASE_NO_PARENT },
+ { PHASE_UNMARK_GRAY, "Unmark gray", PHASE_BARRIER },
+ { PHASE_MARK_ROOTS, "Mark Roots", PHASE_MULTI_PARENTS },
+ { PHASE_BUFFER_GRAY_ROOTS, "Buffer Gray Roots", PHASE_MARK_ROOTS },
+ { PHASE_MARK_CCWS, "Mark Cross Compartment Wrappers", PHASE_MARK_ROOTS },
+ { PHASE_MARK_STACK, "Mark C and JS stacks", PHASE_MARK_ROOTS },
+ { PHASE_MARK_RUNTIME_DATA, "Mark Runtime-wide Data", PHASE_MARK_ROOTS },
+ { PHASE_MARK_EMBEDDING, "Mark Embedding", PHASE_MARK_ROOTS },
+ { PHASE_MARK_COMPARTMENTS, "Mark Compartments", PHASE_MARK_ROOTS },
+ { PHASE_PURGE_SHAPE_TABLES, "Purge ShapeTables", PHASE_NO_PARENT },
+
+ { PHASE_LIMIT, nullptr, PHASE_NO_PARENT }
};
static ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } };
@@ -845,12 +833,6 @@ Statistics::~Statistics()
/* static */ bool
Statistics::initialize()
{
- for (size_t i = 0; i < PHASE_LIMIT; i++) {
- MOZ_ASSERT(phases[i].index == i);
- for (size_t j = 0; j < PHASE_LIMIT; j++)
- MOZ_ASSERT_IF(i != j, phases[i].telemetryBucket != phases[j].telemetryBucket);
- }
-
// Create a static table of descendants for every phase with multiple
// children. This assumes that all descendants come linearly in the
// list, which is reasonable since full dags are not supported; any
@@ -925,32 +907,6 @@ Statistics::getMaxGCPauseSinceClear()
return maxPauseInInterval;
}
-// Sum up the time for a phase, including instances of the phase with different
-// parents.
-static int64_t
-SumPhase(Phase phase, const Statistics::PhaseTimeTable times)
-{
- int64_t sum = 0;
- for (auto i : MakeRange(Statistics::NumTimingArrays))
- sum += times[i][phase];
- return sum;
-}
-
-static Phase
-LongestPhase(const Statistics::PhaseTimeTable times)
-{
- int64_t longestTime = 0;
- Phase longestPhase = PHASE_NONE;
- for (size_t i = 0; i < PHASE_LIMIT; ++i) {
- int64_t phaseTime = SumPhase(Phase(i), times);
- if (phaseTime > longestTime) {
- longestTime = phaseTime;
- longestPhase = Phase(i);
- }
- }
- return longestPhase;
-}
-
void
Statistics::printStats()
{
@@ -985,34 +941,6 @@ Statistics::endGC()
int64_t total, longest;
gcDuration(&total, &longest);
- int64_t sccTotal, sccLongest;
- sccDurations(&sccTotal, &sccLongest);
-
- runtime->addTelemetry(JS_TELEMETRY_GC_IS_ZONE_GC, !zoneStats.isCollectingAllZones());
- runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total));
- runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest));
- int64_t markTotal = SumPhase(PHASE_MARK, phaseTimes);
- int64_t markRootsTotal = SumPhase(PHASE_MARK_ROOTS, phaseTimes);
- runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, t(markTotal));
- runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP]));
- if (runtime->gc.isCompactingGc()) {
- runtime->addTelemetry(JS_TELEMETRY_GC_COMPACT_MS,
- t(phaseTimes[PHASE_DAG_NONE][PHASE_COMPACT]));
- }
- runtime->addTelemetry(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(markRootsTotal));
- runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP_MARK_GRAY]));
- runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL, nonincremental());
- if (nonincremental())
- runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL_REASON, uint32_t(nonincrementalReason_));
- runtime->addTelemetry(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.isIncrementalGCAllowed());
- runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal));
- runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest));
-
- if (!aborted) {
- double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC);
- runtime->addTelemetry(JS_TELEMETRY_GC_MMU_50, mmu50 * 100);
- }
-
if (fp)
printStats();
@@ -1061,8 +989,6 @@ Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
return;
}
- runtime->addTelemetry(JS_TELEMETRY_GC_REASON, reason);
-
// Slice callbacks should only fire for the outermost level.
if (gcDepth == 1) {
bool wasFullGC = zoneStats.isCollectingAllZones();
@@ -1082,25 +1008,6 @@ Statistics::endSlice()
slices.back().endFaults = GetPageFaultCount();
slices.back().finalState = runtime->gc.state();
- int64_t sliceTime = slices.back().end - slices.back().start;
- runtime->addTelemetry(JS_TELEMETRY_GC_SLICE_MS, t(sliceTime));
- runtime->addTelemetry(JS_TELEMETRY_GC_RESET, slices.back().wasReset());
- if (slices.back().wasReset())
- runtime->addTelemetry(JS_TELEMETRY_GC_RESET_REASON, uint32_t(slices.back().resetReason));
-
- if (slices.back().budget.isTimeBudget()) {
- int64_t budget_ms = slices.back().budget.timeBudget.budget;
- runtime->addTelemetry(JS_TELEMETRY_GC_BUDGET_MS, budget_ms);
- if (budget_ms == runtime->gc.defaultSliceBudget())
- runtime->addTelemetry(JS_TELEMETRY_GC_ANIMATION_MS, t(sliceTime));
-
- // Record any phase that goes more than 2x over its budget.
- if (sliceTime > 2 * budget_ms * 1000) {
- Phase longest = LongestPhase(slices.back().phaseTimes);
- runtime->addTelemetry(JS_TELEMETRY_GC_SLOW_PHASE, phases[longest].telemetryBucket);
- }
- }
-
sliceCount_++;
}
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index 30c4a835a7..005d2278e4 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2154,6 +2154,13 @@ namespace JS {
extern JS_PUBLIC_API(bool)
OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool* bp);
+// Implementation of
+// https://www.ecma-international.org/ecma-262/6.0/#sec-instanceofoperator
+// This is almost identical to JS_HasInstance, except the latter may call a
+// custom hasInstance class op instead of InstanceofOperator.
+extern JS_PUBLIC_API(bool)
+InstanceofOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp);
+
} // namespace JS
extern JS_PUBLIC_API(void*)
@@ -6566,7 +6573,7 @@ struct JS_PUBLIC_API(PerformanceGroup) {
uint64_t refCount_;
};
-using PerformanceGroupVector = mozilla::Vector<RefPtr<js::PerformanceGroup>, 0, SystemAllocPolicy>;
+using PerformanceGroupVector = mozilla::Vector<RefPtr<js::PerformanceGroup>, 8, SystemAllocPolicy>;
/**
* Commit any Performance Monitoring data.
@@ -6605,10 +6612,6 @@ SetStopwatchIsMonitoringJank(JSContext*, bool);
extern JS_PUBLIC_API(bool)
GetStopwatchIsMonitoringJank(JSContext*);
-// Extract the CPU rescheduling data.
-extern JS_PUBLIC_API(void)
-GetPerfMonitoringTestCpuRescheduling(JSContext*, uint64_t* stayed, uint64_t* moved);
-
/**
* Add a number of microseconds to the time spent waiting on CPOWs
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index 4e4ccdf2a3..a48bb0ffec 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -41,7 +41,6 @@ using namespace js::gc;
using namespace js::jit;
using mozilla::DebugOnly;
-using mozilla::PodArrayZero;
JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = JS::CompartmentOptions())
: creationOptions_(options.creationOptions()),
@@ -91,7 +90,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
unmappedArgumentsTemplate_(nullptr),
lcovOutput()
{
- PodArrayZero(sawDeprecatedLanguageExtension);
runtime_->numCompartments++;
MOZ_ASSERT_IF(creationOptions_.mergeable(),
creationOptions_.invisibleToDebugger());
@@ -99,8 +97,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
JSCompartment::~JSCompartment()
{
- reportTelemetry();
-
// Write the code coverage information in a file.
JSRuntime* rt = runtimeFromMainThread();
if (rt->lcovOutput.isEnabled())
@@ -1268,39 +1264,6 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
*privateData += callback(mallocSizeOf, this);
}
-void
-JSCompartment::reportTelemetry()
-{
- // Only report telemetry for web content and add-ons, not chrome JS.
- if (isSystem_)
- return;
-
- // Hazard analysis can't tell that the telemetry callbacks don't GC.
- JS::AutoSuppressGCAnalysis nogc;
-
- int id = creationOptions_.addonIdOrNull()
- ? JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS
- : JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT;
-
- // Call back into Firefox's Telemetry reporter.
- for (size_t i = 0; i < DeprecatedLanguageExtensionCount; i++) {
- if (sawDeprecatedLanguageExtension[i])
- runtime_->addTelemetry(id, i);
- }
-}
-
-void
-JSCompartment::addTelemetry(const char* filename, DeprecatedLanguageExtension e)
-{
- // Only report telemetry for web content and add-ons, not chrome JS.
- if (isSystem_)
- return;
- if (!creationOptions_.addonIdOrNull() && (!filename || strncmp(filename, "http", 4) != 0))
- return;
-
- sawDeprecatedLanguageExtension[e] = true;
-}
-
HashNumber
JSCompartment::randomHashCode()
{
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index 7bfeee1f68..98c8fe200d 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -344,13 +344,6 @@ struct JSCompartment
isAtomsCompartment_ = true;
}
- // Used to approximate non-content code when reporting telemetry.
- inline bool isProbablySystemOrAddonCode() const {
- if (creationOptions_.addonIdOrNull())
- return true;
-
- return isSystem_;
- }
private:
JSPrincipals* principals_;
bool isSystem_;
@@ -879,34 +872,10 @@ struct JSCompartment
return jitCompartment_;
}
- enum DeprecatedLanguageExtension {
- DeprecatedForEach = 0, // JS 1.6+
- // NO LONGER USING 1
- DeprecatedLegacyGenerator = 2, // JS 1.7+
- DeprecatedExpressionClosure = 3, // Added in JS 1.8
- // NO LONGER USING 4
- // NO LONGER USING 5
- // NO LONGER USING 6
- // NO LONGER USING 7
- // NO LONGER USING 8
- // NO LONGER USING 9
- DeprecatedBlockScopeFunRedecl = 10,
- DeprecatedLanguageExtensionCount
- };
-
js::ArgumentsObject* getOrCreateArgumentsTemplateObject(JSContext* cx, bool mapped);
js::ArgumentsObject* maybeArgumentsTemplateObject(bool mapped) const;
- private:
- // Used for collecting telemetry on SpiderMonkey's deprecated language extensions.
- bool sawDeprecatedLanguageExtension[DeprecatedLanguageExtensionCount];
-
- void reportTelemetry();
-
- public:
- void addTelemetry(const char* filename, DeprecatedLanguageExtension e);
-
public:
// Aggregated output used to collect JSScript hit counts when code coverage
// is enabled.
diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp
index 9a8e364edd..1e70a3890b 100644
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -707,67 +707,6 @@ ErrorReport::~ErrorReport()
{
}
-void
-ErrorReport::ReportAddonExceptionToTelementry(JSContext* cx)
-{
- MOZ_ASSERT(exnObject);
- RootedObject unwrapped(cx, UncheckedUnwrap(exnObject));
- MOZ_ASSERT(unwrapped, "UncheckedUnwrap failed?");
-
- // There is not much we can report if the exception is not an ErrorObject, let's ignore those.
- if (!unwrapped->is<ErrorObject>())
- return;
-
- Rooted<ErrorObject*> errObj(cx, &unwrapped->as<ErrorObject>());
- RootedObject stack(cx, errObj->stack());
-
- // Let's ignore TOP level exceptions. For regular add-ons those will not be reported anyway,
- // for SDK based once it should not be a valid case either.
- // At this point the frame stack is unwound but the exception object stored the stack so let's
- // use that for getting the function name.
- if (!stack)
- return;
-
- JSCompartment* comp = stack->compartment();
- JSAddonId* addonId = comp->creationOptions().addonIdOrNull();
-
- // We only want to send the report if the scope that just have thrown belongs to an add-on.
- // Let's check the compartment of the youngest function on the stack, to determine that.
- if (!addonId)
- return;
-
- RootedString funnameString(cx);
- JS::SavedFrameResult result = GetSavedFrameFunctionDisplayName(cx, stack, &funnameString);
- // AccessDenied should never be the case here for add-ons but let's not risk it.
- JSAutoByteString bytes;
- const char* funname = nullptr;
- bool denied = result == JS::SavedFrameResult::AccessDenied;
- funname = denied ? "unknown"
- : funnameString ? AtomToPrintableString(cx,
- &funnameString->asAtom(),
- &bytes)
- : "anonymous";
-
- UniqueChars addonIdChars(JS_EncodeString(cx, addonId));
-
- const char* filename = nullptr;
- if (reportp && reportp->filename) {
- filename = strrchr(reportp->filename, '/');
- if (filename)
- filename++;
- }
- if (!filename) {
- filename = "FILE_NOT_FOUND";
- }
- char histogramKey[64];
- SprintfLiteral(histogramKey, "%s %s %s %u",
- addonIdChars.get(),
- funname,
- filename,
- (reportp ? reportp->lineno : 0) );
- cx->runtime()->addTelemetry(JS_TELEMETRY_ADDON_EXCEPTIONS, 1, histogramKey);
-}
-
bool
ErrorReport::init(JSContext* cx, HandleValue exn,
SniffingBehavior sniffingBehavior)
@@ -786,10 +725,6 @@ ErrorReport::init(JSContext* cx, HandleValue exn,
JSMSG_ERR_DURING_THROW);
return false;
}
-
- // Let's see if the exception is from add-on code, if so, it should be reported
- // to telementry.
- ReportAddonExceptionToTelementry(cx);
}
diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp
index 595a214102..f5cd56a9b6 100644
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -543,11 +543,6 @@ js::SetPreserveWrapperCallback(JSContext* cx, PreserveWrapperCallback callback)
cx->preserveWrapperCallback = callback;
}
-/*
- * The below code is for temporary telemetry use. It can be removed when
- * sufficient data has been harvested.
- */
-
namespace js {
// Defined in vm/GlobalObject.cpp.
extern size_t sSetProtoCalled;
@@ -643,12 +638,6 @@ js::StringToLinearStringSlow(JSContext* cx, JSString* str)
return str->ensureLinear(cx);
}
-JS_FRIEND_API(void)
-JS_SetAccumulateTelemetryCallback(JSContext* cx, JSAccumulateTelemetryDataCallback callback)
-{
- cx->setTelemetryCallback(cx, callback);
-}
-
JS_FRIEND_API(JSObject*)
JS_CloneObject(JSContext* cx, HandleObject obj, HandleObject protoArg)
{
diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
index 7220855491..d292854837 100644
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -105,46 +105,6 @@ JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr shape
extern JS_FRIEND_API(void)
JS_TraceObjectGroupCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr group);
-enum {
- JS_TELEMETRY_GC_REASON,
- JS_TELEMETRY_GC_IS_ZONE_GC,
- JS_TELEMETRY_GC_MS,
- JS_TELEMETRY_GC_BUDGET_MS,
- JS_TELEMETRY_GC_ANIMATION_MS,
- JS_TELEMETRY_GC_MAX_PAUSE_MS,
- JS_TELEMETRY_GC_MARK_MS,
- JS_TELEMETRY_GC_SWEEP_MS,
- JS_TELEMETRY_GC_COMPACT_MS,
- JS_TELEMETRY_GC_MARK_ROOTS_MS,
- JS_TELEMETRY_GC_MARK_GRAY_MS,
- JS_TELEMETRY_GC_SLICE_MS,
- JS_TELEMETRY_GC_SLOW_PHASE,
- JS_TELEMETRY_GC_MMU_50,
- JS_TELEMETRY_GC_RESET,
- JS_TELEMETRY_GC_RESET_REASON,
- JS_TELEMETRY_GC_INCREMENTAL_DISABLED,
- JS_TELEMETRY_GC_NON_INCREMENTAL,
- JS_TELEMETRY_GC_NON_INCREMENTAL_REASON,
- JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS,
- JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS,
- JS_TELEMETRY_GC_MINOR_REASON,
- JS_TELEMETRY_GC_MINOR_REASON_LONG,
- JS_TELEMETRY_GC_MINOR_US,
- JS_TELEMETRY_GC_NURSERY_BYTES,
- JS_TELEMETRY_GC_PRETENURE_COUNT,
- JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT,
- JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS,
- JS_TELEMETRY_ADDON_EXCEPTIONS,
- JS_TELEMETRY_AOT_USAGE,
- JS_TELEMETRY_END
-};
-
-typedef void
-(*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key);
-
-extern JS_FRIEND_API(void)
-JS_SetAccumulateTelemetryCallback(JSContext* cx, JSAccumulateTelemetryDataCallback callback);
-
extern JS_FRIEND_API(bool)
JS_GetIsSecureContext(JSCompartment* compartment);
@@ -1456,9 +1416,6 @@ struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport)
bool populateUncaughtExceptionReportUTF8(JSContext* cx, ...);
bool populateUncaughtExceptionReportUTF8VA(JSContext* cx, va_list ap);
- // Reports exceptions from add-on scopes to telementry.
- void ReportAddonExceptionToTelementry(JSContext* cx);
-
// We may have a provided JSErrorReport, so need a way to represent that.
JSErrorReport* reportp;
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index bcb0da80b2..863871df93 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -690,7 +690,7 @@ js::fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp)
}
/*
- * ES6 (4-25-16) 7.3.19 OrdinaryHasInstance
+ * ES6 7.3.19 OrdinaryHasInstance
*/
bool
JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool* bp)
@@ -707,7 +707,7 @@ JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool*
if (obj->is<JSFunction>() && obj->isBoundFunction()) {
/* Steps 2a-b. */
obj = obj->as<JSFunction>().getBoundFunctionTarget();
- return InstanceOfOperator(cx, obj, v, bp);
+ return InstanceofOperator(cx, obj, v, bp);
}
/* Step 3. */
@@ -716,12 +716,12 @@ JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool*
return true;
}
- /* Step 4. */
+ /* Step 4-5. */
RootedValue pval(cx);
if (!GetProperty(cx, obj, obj, cx->names().prototype, &pval))
return false;
- /* Step 5. */
+ /* Step 6. */
if (pval.isPrimitive()) {
/*
* Throw a runtime error if instanceof is called on a function that
@@ -732,7 +732,7 @@ JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool*
return false;
}
- /* Step 6. */
+ /* Step 7. */
RootedObject pobj(cx, &pval.toObject());
bool isDelegate;
if (!IsDelegate(cx, pobj, v, &isDelegate))
diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp
index 3d4dae9bb9..8cee9ec096 100644
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2310,22 +2310,27 @@ GCRuntime::updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, s
// 2) typed object type descriptor objects
// 3) all other objects
//
+// Also, there can be data races calling IsForwarded() on the new location of a
+// cell that is being updated in parallel on another thread. This can be avoided
+// by updating some kinds of cells in different phases. This is done for JSScripts
+// and LazyScripts, and JSScripts and Scopes.
+//
// Since we want to minimize the number of phases, we put everything else into
// the first phase and label it the 'misc' phase.
static const AllocKinds UpdatePhaseMisc {
AllocKind::SCRIPT,
- AllocKind::LAZY_SCRIPT,
AllocKind::BASE_SHAPE,
AllocKind::SHAPE,
AllocKind::ACCESSOR_SHAPE,
AllocKind::OBJECT_GROUP,
AllocKind::STRING,
- AllocKind::JITCODE,
- AllocKind::SCOPE
+ AllocKind::JITCODE
};
static const AllocKinds UpdatePhaseObjects {
+ AllocKind::LAZY_SCRIPT,
+ AllocKind::SCOPE,
AllocKind::FUNCTION,
AllocKind::FUNCTION_EXTENDED,
AllocKind::OBJECT0,
diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp
index 4151d012b6..e3b5708ca2 100644
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -3070,8 +3070,11 @@ js::ValueToSource(JSContext* cx, HandleValue v)
return ToString<CanGC>(cx, v);
}
-
+#if JS_HAS_TOSOURCE
return ObjectToSource(cx, obj);
+#else
+ return ToString<CanGC>(cx, v);
+#endif
}
JSString*
diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h
index 3c73979f88..84ebe27324 100644
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -270,6 +270,8 @@ class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrap
virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
virtual bool isArray(JSContext* cx, HandleObject obj,
JS::IsArrayAnswer* answer) const override;
+ virtual bool hasInstance(JSContext* cx, HandleObject wrapper,
+ MutableHandleValue v, bool* bp) const override;
virtual const char* className(JSContext* cx, HandleObject wrapper) const override;
virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override;
diff --git a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
index ff3f4145cc..02bf237ff2 100644
--- a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
+++ b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
@@ -175,6 +175,14 @@ OpaqueCrossCompartmentWrapper::isArray(JSContext* cx, HandleObject obj,
return true;
}
+bool OpaqueCrossCompartmentWrapper::hasInstance(JSContext* cx,
+ HandleObject wrapper,
+ MutableHandleValue v,
+ bool* bp) const {
+ *bp = false;
+ return true;
+}
+
const char*
OpaqueCrossCompartmentWrapper::className(JSContext* cx,
HandleObject proxy) const
diff --git a/js/src/proxy/ScriptedProxyHandler.cpp b/js/src/proxy/ScriptedProxyHandler.cpp
index 7765473371..0e25f470c0 100644
--- a/js/src/proxy/ScriptedProxyHandler.cpp
+++ b/js/src/proxy/ScriptedProxyHandler.cpp
@@ -8,8 +8,6 @@
#include "jsapi.h"
-#include "vm/Interpreter.h" // For InstanceOfOperator
-
#include "jsobjinlines.h"
#include "vm/NativeObject-inl.h"
@@ -1230,7 +1228,7 @@ bool
ScriptedProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
bool* bp) const
{
- return InstanceOfOperator(cx, proxy, v, bp);
+ return InstanceofOperator(cx, proxy, v, bp);
}
bool
diff --git a/js/src/tests/user.js b/js/src/tests/user.js
index 732bbbd1a2..e75593ab18 100755
--- a/js/src/tests/user.js
+++ b/js/src/tests/user.js
@@ -22,7 +22,6 @@ user_pref("javascript.options.strict", false);
user_pref("javascript.options.werror", false);
user_pref("toolkit.startup.max_resumed_crashes", -1);
user_pref("security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", true);
-user_pref("toolkit.telemetry.enabled", false);
user_pref("browser.safebrowsing.phishing.enabled", false);
user_pref("browser.safebrowsing.malware.enabled", false);
user_pref("browser.safebrowsing.forbiddenURIs.enabled", false);
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
index b747e4d7a0..e6d6630c4b 100644
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -718,14 +718,14 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& envChainArg, Value* rv
}
/*
- * ES6 (4-25-16) 12.10.4 InstanceofOperator
+ * ES6 12.9.4 InstanceofOperator
*/
extern bool
-js::InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp)
+JS::InstanceofOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp)
{
/* Step 1. is handled by caller. */
- /* Step 2. */
+ /* Step 2-3. */
RootedValue hasInstance(cx);
RootedId id(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().hasInstance));
if (!GetProperty(cx, obj, obj, id, &hasInstance))
@@ -735,7 +735,7 @@ js::InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp)
if (!IsCallable(hasInstance))
return ReportIsNotFunction(cx, hasInstance);
- /* Step 3. */
+ /* Step 4. */
RootedValue rval(cx);
if (!Call(cx, hasInstance, obj, v, &rval))
return false;
@@ -743,13 +743,13 @@ js::InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp)
return true;
}
- /* Step 4. */
+ /* Step 5. */
if (!obj->isCallable()) {
RootedValue val(cx, ObjectValue(*obj));
return ReportIsNotFunction(cx, val);
}
- /* Step 5. */
+ /* Step 6. */
return OrdinaryHasInstance(cx, obj, v, bp);
}
@@ -760,7 +760,7 @@ js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp)
RootedValue local(cx, v);
if (JSHasInstanceOp hasInstance = clasp->getHasInstance())
return hasInstance(cx, obj, &local, bp);
- return js::InstanceOfOperator(cx, obj, local, bp);
+ return JS::InstanceofOperator(cx, obj, local, bp);
}
static inline bool
diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h
index 330dbef5f5..9fefd75ccd 100644
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -323,9 +323,6 @@ extern JSType
TypeOfValue(const Value& v);
extern bool
-InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp);
-
-extern bool
HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp);
// Unwind environment chain and iterator to match the scope corresponding to
diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
index 174e235942..8eb997c71b 100644
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -147,7 +147,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
updateChildRuntimeCount(parentRuntime),
#endif
interrupt_(false),
- telemetryCallback(nullptr),
handlingSegFault(false),
handlingJitInterrupt_(false),
interruptCallbackDisabled(false),
@@ -452,19 +451,6 @@ JSRuntime::destroyRuntime()
}
void
-JSRuntime::addTelemetry(int id, uint32_t sample, const char* key)
-{
- if (telemetryCallback)
- (*telemetryCallback)(id, sample, key);
-}
-
-void
-JSRuntime::setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback)
-{
- rt->telemetryCallback = callback;
-}
-
-void
JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes)
{
// Several tables in the runtime enumerated below can be used off thread.
diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
index f354d20695..e60371e38c 100644
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -577,17 +577,7 @@ struct JSRuntime : public JS::shadow::Runtime,
#endif
mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_;
-
- /* Call this to accumulate telemetry data. */
- JSAccumulateTelemetryDataCallback telemetryCallback;
public:
- // Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
- // histogram. |key| provides an additional key to identify the histogram.
- // |sample| is the data to add to the histogram.
- void addTelemetry(int id, uint32_t sample, const char* key = nullptr);
-
- void setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback);
-
enum InterruptMode {
RequestInterruptUrgent,
RequestInterruptCanWait
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
index 08670c8331..328a960b6b 100644
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1904,23 +1904,6 @@ intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp)
}
static bool
-intrinsic_AddContentTelemetry(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- MOZ_ASSERT(args.length() == 2);
-
- int id = args[0].toInt32();
- MOZ_ASSERT(id < JS_TELEMETRY_END);
- MOZ_ASSERT(id >= 0);
-
- if (!cx->compartment()->isProbablySystemOrAddonCode())
- cx->runtime()->addTelemetry(id, args[1].toInt32());
-
- args.rval().setUndefined();
- return true;
-}
-
-static bool
intrinsic_ConstructFunction(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
@@ -2273,7 +2256,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
JS_FN("_FinishBoundFunctionInit", intrinsic_FinishBoundFunctionInit, 3,0),
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
- JS_FN("AddContentTelemetry", intrinsic_AddContentTelemetry, 2,0),
JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0,
IntrinsicIsConstructing),
diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp
index 28632c2a15..684846f000 100644
--- a/js/src/vm/Stopwatch.cpp
+++ b/js/src/vm/Stopwatch.cpp
@@ -20,6 +20,7 @@
#include "gc/Zone.h"
#include "vm/Runtime.h"
+
namespace js {
bool
@@ -136,6 +137,9 @@ PerformanceMonitoring::start()
bool
PerformanceMonitoring::commit()
{
+ // Maximal initialization size, in elements for the vector of groups.
+ static const size_t MAX_GROUPS_INIT_CAPACITY = 1024;
+
#if !defined(MOZ_HAVE_RDTSC)
// The AutoStopwatch is only executed if `MOZ_HAVE_RDTSC`.
return false;
@@ -152,13 +156,24 @@ PerformanceMonitoring::commit()
return true;
}
- PerformanceGroupVector recentGroups;
- recentGroups_.swap(recentGroups);
+ // The move operation is generally constant time, unless
+ // `recentGroups_.length()` is very small, in which case
+ // it's fast just because it's small.
+ PerformanceGroupVector recentGroups(Move(recentGroups_));
+ recentGroups_ = PerformanceGroupVector(); // Reconstruct after `Move`.
bool success = true;
if (stopwatchCommitCallback)
success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure);
+ // Heuristic: we expect to have roughly the same number of groups as in
+ // the previous iteration.
+ const size_t capacity = recentGroups.capacity() < MAX_GROUPS_INIT_CAPACITY ?
+ recentGroups.capacity() :
+ MAX_GROUPS_INIT_CAPACITY;
+ success = recentGroups_.reserve(capacity)
+ && success;
+
// Reset immediately, to make sure that we're not hit by the end
// of a nested event loop (which would cause `commit` to be called
// twice in succession).
@@ -227,7 +242,7 @@ AutoStopwatch::AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IM
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
JSCompartment* compartment = cx_->compartment();
- if (compartment->scheduledForDestruction)
+ if (MOZ_UNLIKELY(compartment->scheduledForDestruction))
return;
JSRuntime* runtime = cx_->runtime();
@@ -266,11 +281,11 @@ AutoStopwatch::~AutoStopwatch()
}
JSCompartment* compartment = cx_->compartment();
- if (compartment->scheduledForDestruction)
+ if (MOZ_UNLIKELY(compartment->scheduledForDestruction))
return;
JSRuntime* runtime = cx_->runtime();
- if (iteration_ != runtime->performanceMonitoring.iteration()) {
+ if (MOZ_UNLIKELY(iteration_ != runtime->performanceMonitoring.iteration())) {
// We have entered a nested event loop at some point.
// Any information we may have is obsolete.
return;
@@ -319,11 +334,6 @@ AutoStopwatch::exit()
const uint64_t cyclesEnd = getCycles(runtime);
cyclesDelta = cyclesEnd - cyclesStart_; // Always >= 0 by definition of `getCycles`.
}
-#if WINVER >= 0x600
- updateTelemetry(cpuStart_, cpuEnd);
-#elif defined(__linux__)
- updateTelemetry(cpuStart_, cpuEnd);
-#endif // WINVER >= 0x600 || _linux__
}
uint64_t CPOWTimeDelta = 0;
@@ -335,17 +345,6 @@ AutoStopwatch::exit()
return addToGroups(cyclesDelta, CPOWTimeDelta);
}
-void
-AutoStopwatch::updateTelemetry(const cpuid_t& cpuStart_, const cpuid_t& cpuEnd)
-{
- JSRuntime* runtime = cx_->runtime();
-
- if (isSameCPU(cpuStart_, cpuEnd))
- runtime->performanceMonitoring.testCpuRescheduling.stayed += 1;
- else
- runtime->performanceMonitoring.testCpuRescheduling.moved += 1;
-}
-
PerformanceGroup*
AutoStopwatch::acquireGroup(PerformanceGroup* group)
{
@@ -638,13 +637,6 @@ GetStopwatchIsMonitoringCPOW(JSContext* cx)
}
JS_PUBLIC_API(void)
-GetPerfMonitoringTestCpuRescheduling(JSContext* cx, uint64_t* stayed, uint64_t* moved)
-{
- *stayed = cx->performanceMonitoring.testCpuRescheduling.stayed;
- *moved = cx->performanceMonitoring.testCpuRescheduling.moved;
-}
-
-JS_PUBLIC_API(void)
AddCPOWPerformanceDelta(JSContext* cx, uint64_t delta)
{
cx->performanceMonitoring.totalCPOWTime += delta;
diff --git a/js/src/vm/Stopwatch.h b/js/src/vm/Stopwatch.h
index 38a3eb801c..d7f299594b 100644
--- a/js/src/vm/Stopwatch.h
+++ b/js/src/vm/Stopwatch.h
@@ -217,33 +217,6 @@ struct PerformanceMonitoring {
*/
uint64_t monotonicReadTimestampCounter();
- /**
- * Data extracted by the AutoStopwatch to determine how often
- * we reschedule the process to a different CPU during the
- * execution of JS.
- *
- * Warning: These values are incremented *only* on platforms
- * that offer a syscall/libcall to check on which CPU a
- * process is currently executed.
- */
- struct TestCpuRescheduling
- {
- // Incremented once we have finished executing code
- // in a group, if the CPU on which we started
- // execution is the same as the CPU on which
- // we finished.
- uint64_t stayed;
- // Incremented once we have finished executing code
- // in a group, if the CPU on which we started
- // execution is different from the CPU on which
- // we finished.
- uint64_t moved;
- TestCpuRescheduling()
- : stayed(0),
- moved(0)
- { }
- };
- TestCpuRescheduling testCpuRescheduling;
private:
PerformanceMonitoring(const PerformanceMonitoring&) = delete;
PerformanceMonitoring& operator=(const PerformanceMonitoring&) = delete;
@@ -375,9 +348,6 @@ class AutoStopwatch final {
// Add recent changes to a single group. Mark the group as changed recently.
bool addToGroup(JSRuntime* runtime, uint64_t cyclesDelta, uint64_t CPOWTimeDelta, PerformanceGroup* group);
- // Update telemetry statistics.
- void updateTelemetry(const cpuid_t& a, const cpuid_t& b);
-
// Perform a subtraction for a quantity that should be monotonic
// but is not guaranteed to be so.
//
diff --git a/js/src/wasm/WasmBinaryConstants.h b/js/src/wasm/WasmBinaryConstants.h
index fd3bd1264a..9aa5091f65 100644
--- a/js/src/wasm/WasmBinaryConstants.h
+++ b/js/src/wasm/WasmBinaryConstants.h
@@ -434,15 +434,6 @@ enum class Op
Limit
};
-// Telemetry sample values for the JS_AOT_USAGE key, indicating whether asm.js
-// or WebAssembly is used.
-
-enum class Telemetry
-{
- ASMJS = 0,
- WASM = 1
-};
-
} // namespace wasm
} // namespace js
diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp
index b24e01a400..f1ecd86203 100644
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -1066,8 +1066,5 @@ Module::instantiate(JSContext* cx,
return false;
}
- uint32_t mode = uint32_t(metadata().isAsmJS() ? Telemetry::ASMJS : Telemetry::WASM);
- cx->runtime()->addTelemetry(JS_TELEMETRY_AOT_USAGE, mode);
-
return true;
}
diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.cpp b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
index 9c8908ea41..f23e5833a0 100644
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -295,7 +295,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AsyncScriptLoader)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(AsyncScriptLoader)
diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp
index 120772ed2f..a516cf73fb 100644
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -66,7 +66,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SandboxPrivate)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SandboxPrivate)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
tmp->TraverseHostObjectURIs(cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp
index 82af645209..0243d80e36 100644
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -132,7 +132,6 @@ class AsyncFreeSnowWhite : public Runnable
public:
NS_IMETHOD Run() override
{
- TimeStamp start = TimeStamp::Now();
bool hadSnowWhiteObjects = nsCycleCollector_doDeferredDeletion();
if (hadSnowWhiteObjects && !mContinuation) {
mContinuation = true;
@@ -1235,8 +1234,6 @@ XPCJSContext::InterruptCallback(JSContext* cx)
if (self->mSlowScriptCheckpoint.IsNull()) {
self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
self->mSlowScriptSecondHalf = false;
- self->mSlowScriptActualWait = mozilla::TimeDuration();
- self->mTimeoutAccumulated = false;
return true;
}
@@ -1258,8 +1255,6 @@ XPCJSContext::InterruptCallback(JSContext* cx)
if (limit == 0 || duration.ToSeconds() < limit / 2.0)
return true;
- self->mSlowScriptActualWait += duration;
-
// In order to guard against time changes or laptops going to sleep, we
// don't trigger the slow script warning until (limit/2) seconds have
// elapsed twice.
@@ -1311,12 +1306,6 @@ XPCJSContext::InterruptCallback(JSContext* cx)
return false;
}
- // Accumulate slow script invokation delay.
- if (!chrome && !self->mTimeoutAccumulated) {
- uint32_t delay = uint32_t(self->mSlowScriptActualWait.ToMilliseconds() - (limit * 1000.0));
- self->mTimeoutAccumulated = true;
- }
-
// Show the prompt to the user, and kill if requested.
nsGlobalWindow::SlowScriptResponse response = win->ShowSlowScriptDialog();
if (response == nsGlobalWindow::KillSlowScript) {
@@ -2949,12 +2938,6 @@ JSSizeOfTab(JSObject* objArg, size_t* jsObjectsSize, size_t* jsStringsSize,
} // namespace xpc
static void
-AccumulateTelemetryCallback(int id, uint32_t sample, const char* key)
-{
-/* STUB */
-}
-
-static void
CompartmentNameCallback(JSContext* cx, JSCompartment* comp,
char* buf, size_t bufsize)
{
@@ -3113,7 +3096,6 @@ XPCJSContext::XPCJSContext()
mWatchdogManager(new WatchdogManager(this)),
mAsyncSnowWhiteFreer(new AsyncFreeSnowWhite()),
mSlowScriptSecondHalf(false),
- mTimeoutAccumulated(false),
mPendingResult(NS_OK)
{
}
@@ -3279,7 +3261,6 @@ XPCJSContext::Initialize()
JS_AddWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback, this);
JS_SetWrapObjectCallbacks(cx, &WrapObjectCallbacks);
js::SetPreserveWrapperCallback(cx, PreserveWrapper);
- JS_SetAccumulateTelemetryCallback(cx, AccumulateTelemetryCallback);
js::SetActivityCallback(cx, ActivityCallback, this);
JS_AddInterruptCallback(cx, InterruptCallback);
js::SetWindowProxyClass(cx, &OuterWindowProxyClass);
@@ -3444,8 +3425,6 @@ XPCJSContext::BeforeProcessTask(bool aMightBlock)
// Start the slow script timer.
mSlowScriptCheckpoint = mozilla::TimeStamp::NowLoRes();
mSlowScriptSecondHalf = false;
- mSlowScriptActualWait = mozilla::TimeDuration();
- mTimeoutAccumulated = false;
// As we may be entering a nested event loop, we need to
// cancel any ongoing performance measurement.
diff --git a/js/xpconnect/src/nsScriptErrorWithStack.cpp b/js/xpconnect/src/nsScriptErrorWithStack.cpp
index edc12fa767..50407da23c 100644
--- a/js/xpconnect/src/nsScriptErrorWithStack.cpp
+++ b/js/xpconnect/src/nsScriptErrorWithStack.cpp
@@ -45,7 +45,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsScriptErrorWithStack)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsScriptErrorWithStack)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsScriptErrorWithStack)
diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h
index d7d5586b8f..347b406eb5 100644
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -634,9 +634,6 @@ private:
// (whichever comes later). We use it to determine whether the interrupt
// callback needs to do anything.
mozilla::TimeStamp mSlowScriptCheckpoint;
- // Accumulates total time we actually waited for telemetry
- mozilla::TimeDuration mSlowScriptActualWait;
- bool mTimeoutAccumulated;
// mPendingResult is used to implement Components.returnCode. Only really
// meaningful while calling through XPCWrappedJS.
diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
index 27c010d341..dca3daa58c 100644
--- a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
+++ b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
@@ -88,6 +88,37 @@ WaiveXrayWrapper::nativeCall(JSContext* cx, JS::IsAcceptableThis test,
}
bool
+WaiveXrayWrapper::hasInstance(JSContext* cx, HandleObject wrapper,
+ MutableHandleValue v, bool* bp) const {
+ if (v.isObject() && WrapperFactory::IsXrayWrapper(&v.toObject())) {
+ // If |v| is an XrayWrapper and in the same compartment as the value
+ // wrapped by |wrapper|, then the Xrays of |v| would be waived upon
+ // calling CrossCompartmentWrapper::hasInstance. This may trigger
+ // getters and proxy traps of unwrapped |v|. To prevent that from
+ // happening, we exit early.
+
+ // |wrapper| is the right operand of "instanceof", and must either be
+ // a function or an object with a @@hasInstance method. We are not going
+ // to call @@hasInstance, so only check whether it is a function.
+ // This check is here for consistency with usual "instanceof" behavior,
+ // which throws if the right operand is not a function. Without this
+ // check, the "instanceof" operator would return false and potentially
+ // hide errors in the code that uses the "instanceof" operator.
+ if (!JS::IsCallable(wrapper)) {
+ RootedValue wrapperv(cx, JS::ObjectValue(*wrapper));
+ js::ReportIsNotFunction(cx, wrapperv);
+ return false;
+ }
+
+ *bp = false;
+ return true;
+ }
+
+ // Both |wrapper| and |v| have no Xrays here.
+ return CrossCompartmentWrapper::hasInstance(cx, wrapper, v, bp);
+}
+
+bool
WaiveXrayWrapper::getPrototype(JSContext* cx, HandleObject wrapper, MutableHandleObject protop) const
{
return CrossCompartmentWrapper::getPrototype(cx, wrapper, protop) &&
diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.h b/js/xpconnect/wrappers/WaiveXrayWrapper.h
index b0b4477968..0f9675c174 100644
--- a/js/xpconnect/wrappers/WaiveXrayWrapper.h
+++ b/js/xpconnect/wrappers/WaiveXrayWrapper.h
@@ -36,6 +36,8 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper {
JS::MutableHandle<JSObject*> objp) const override;
virtual bool nativeCall(JSContext* cx, JS::IsAcceptableThis test,
JS::NativeImpl impl, const JS::CallArgs& args) const override;
+ virtual bool hasInstance(JSContext* cx, JS::HandleObject wrapper,
+ JS::MutableHandleValue v, bool* bp) const override;
virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id,
JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp
index 48a9fdc68e..6e5a2f5e59 100644
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -2309,6 +2309,20 @@ XrayWrapper<Base, Traits>::getBuiltinClass(JSContext* cx, JS::HandleObject wrapp
}
template <typename Base, typename Traits>
+bool
+XrayWrapper<Base, Traits>::hasInstance(JSContext* cx,
+ JS::HandleObject wrapper,
+ JS::MutableHandleValue v,
+ bool* bp) const {
+ assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET);
+
+ // CrossCompartmentWrapper::hasInstance unwraps |wrapper|'s Xrays and enters
+ // its compartment. Any present XrayWrappers should be preserved, so the
+ // standard "instanceof" implementation is called without unwrapping first.
+ return JS::InstanceofOperator(cx, wrapper, v, bp);
+}
+
+template <typename Base, typename Traits>
const char*
XrayWrapper<Base, Traits>::className(JSContext* cx, HandleObject wrapper) const
{
diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h
index 5630982c28..038d823900 100644
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -482,6 +482,8 @@ class XrayWrapper : public Base {
JS::AutoIdVector& props) const override;
virtual bool getBuiltinClass(JSContext* cx, JS::HandleObject wapper, js::ESClass* cls) const override;
+ virtual bool hasInstance(JSContext* cx, JS::HandleObject wrapper,
+ JS::MutableHandleValue v, bool* bp) const override;
virtual const char* className(JSContext* cx, JS::HandleObject proxy) const override;
static const XrayWrapper singleton;