diff options
Diffstat (limited to 'js')
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; |