tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit b0c596352f76e501680fc2fbe4419e701e488ece
parent 1a068169cb70e2ebb2d5e1fcefa4309fc4f7643e
Author: wilsu <wilsu@outlook.de>
Date:   Thu, 27 Nov 2025 13:56:23 +0000

Bug 998485 - Removed analyzeEdgeCasesForward from MIR.h/.cpp - r=nbp

Differential Revision: https://phabricator.services.mozilla.com/D257010

Diffstat:
Djs/src/jit/EdgeCaseAnalysis.cpp | 51---------------------------------------------------
Djs/src/jit/EdgeCaseAnalysis.h | 28----------------------------
Mjs/src/jit/Ion.cpp | 17-----------------
Mjs/src/jit/IonOptimizationLevels.h | 10----------
Mjs/src/jit/JitOptions.cpp | 3---
Mjs/src/jit/JitOptions.h | 1-
Mjs/src/jit/MIR.cpp | 257-------------------------------------------------------------------------------
Mjs/src/jit/MIR.h | 9---------
Mjs/src/jit/moz.build | 1-
Mjs/src/shell/js.cpp | 10----------
10 files changed, 0 insertions(+), 387 deletions(-)

diff --git a/js/src/jit/EdgeCaseAnalysis.cpp b/js/src/jit/EdgeCaseAnalysis.cpp @@ -1,51 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=8 sts=2 et sw=2 tw=80: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "jit/EdgeCaseAnalysis.h" - -#include "jit/MIR-wasm.h" -#include "jit/MIR.h" -#include "jit/MIRGenerator.h" -#include "jit/MIRGraph.h" - -using namespace js; -using namespace js::jit; - -EdgeCaseAnalysis::EdgeCaseAnalysis(const MIRGenerator* mir, MIRGraph& graph) - : mir(mir), graph(graph) {} - -bool EdgeCaseAnalysis::analyzeLate() { - // Renumber definitions for NeedNegativeZeroCheck under - // analyzeEdgeCasesBackward. - uint32_t nextId = 0; - - for (ReversePostorderIterator block(graph.rpoBegin()); - block != graph.rpoEnd(); block++) { - for (MDefinitionIterator iter(*block); iter; iter++) { - if (mir->shouldCancel("Analyze Late (first loop)")) { - return false; - } - - iter->setId(nextId++); - iter->analyzeEdgeCasesForward(); - } - block->lastIns()->setId(nextId++); - } - - for (PostorderIterator block(graph.poBegin()); block != graph.poEnd(); - block++) { - for (MInstructionReverseIterator riter(block->rbegin()); - riter != block->rend(); riter++) { - if (mir->shouldCancel("Analyze Late (second loop)")) { - return false; - } - - riter->analyzeEdgeCasesBackward(); - } - } - - return true; -} diff --git a/js/src/jit/EdgeCaseAnalysis.h b/js/src/jit/EdgeCaseAnalysis.h @@ -1,28 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=8 sts=2 et sw=2 tw=80: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef jit_EdgeCaseAnalysis_h -#define jit_EdgeCaseAnalysis_h - -namespace js { -namespace jit { - -class MIRGenerator; -class MIRGraph; - -class EdgeCaseAnalysis { - const MIRGenerator* mir; - MIRGraph& graph; - - public: - EdgeCaseAnalysis(const MIRGenerator* mir, MIRGraph& graph); - [[nodiscard]] bool analyzeLate(); -}; - -} // namespace jit -} // namespace js - -#endif /* jit_EdgeCaseAnalysis_h */ diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp @@ -23,7 +23,6 @@ #include "jit/CodeGenerator.h" #include "jit/CompileInfo.h" #include "jit/DominatorTree.h" -#include "jit/EdgeCaseAnalysis.h" #include "jit/EffectiveAddressAnalysis.h" #include "jit/ExecutableAllocator.h" #include "jit/FoldLinearArithConstants.h" @@ -1492,22 +1491,6 @@ bool OptimizeMIR(MIRGenerator* mir) { } } - // Passes after this point must not move instructions; these analyses - // depend on knowing the final order in which instructions will execute. - - if (mir->optimizationInfo().edgeCaseAnalysisEnabled()) { - EdgeCaseAnalysis edgeCaseAnalysis(mir, graph); - if (!edgeCaseAnalysis.analyzeLate()) { - return false; - } - mir->spewPass("Edge Case Analysis (Late)"); - AssertGraphCoherency(graph); - - if (mir->shouldCancel("Edge Case Analysis (Late)")) { - return false; - } - } - if (mir->optimizationInfo().eliminateRedundantChecksEnabled()) { // Note: check elimination has to run after all other passes that move // instructions. Since check uses are replaced with the actual index, diff --git a/js/src/jit/IonOptimizationLevels.h b/js/src/jit/IonOptimizationLevels.h @@ -44,9 +44,6 @@ class OptimizationInfo { // Toggles whether Alignment Mask Analysis is performed. bool ama_; - // Toggles whether Edge Case Analysis is used. - bool edgeCaseAnalysis_; - // Toggles whether redundant checks get removed. bool eliminateRedundantChecks_; @@ -91,7 +88,6 @@ class OptimizationInfo { : level_(OptimizationLevel::Normal), eaa_(false), ama_(false), - edgeCaseAnalysis_(false), eliminateRedundantChecks_(false), eliminateRedundantShapeGuards_(false), eliminateRedundantGCBarriers_(false), @@ -111,7 +107,6 @@ class OptimizationInfo { autoTruncate_ = true; eaa_ = true; - edgeCaseAnalysis_ = true; eliminateRedundantChecks_ = true; eliminateRedundantShapeGuards_ = true; eliminateRedundantGCBarriers_ = true; @@ -137,7 +132,6 @@ class OptimizationInfo { ama_ = true; autoTruncate_ = false; - edgeCaseAnalysis_ = false; eliminateRedundantChecks_ = false; eliminateRedundantShapeGuards_ = false; eliminateRedundantGCBarriers_ = false; @@ -181,10 +175,6 @@ class OptimizationInfo { bool amaEnabled() const { return ama_ && !JitOptions.disableAma; } - bool edgeCaseAnalysisEnabled() const { - return edgeCaseAnalysis_ && !JitOptions.disableEdgeCaseAnalysis; - } - bool eliminateRedundantChecksEnabled() const { return eliminateRedundantChecks_; } diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp @@ -81,9 +81,6 @@ DefaultJitOptions::DefaultJitOptions() { // Toggles whether Effective Address Analysis is globally disabled. SET_DEFAULT(disableEaa, false); - // Toggles whether Edge Case Analysis is gobally disabled. - SET_DEFAULT(disableEdgeCaseAnalysis, false); - // Toggle whether global value numbering is globally disabled. SET_DEFAULT(disableGvn, false); diff --git a/js/src/jit/JitOptions.h b/js/src/jit/JitOptions.h @@ -54,7 +54,6 @@ struct DefaultJitOptions { bool disableJitHints; bool disableAma; bool disableEaa; - bool disableEdgeCaseAnalysis; bool disableGvn; bool disableInlining; bool disableLicm; diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp @@ -662,10 +662,6 @@ MDefinition* MInstruction::foldsToStore(TempAllocator& alloc) { return value; } -void MDefinition::analyzeEdgeCasesForward() {} - -void MDefinition::analyzeEdgeCasesBackward() {} - void MInstruction::setResumePoint(MResumePoint* resumePoint) { MOZ_ASSERT(!resumePoint_); resumePoint_ = resumePoint; @@ -2854,159 +2850,6 @@ MDefinition* MBinaryBitwiseInstruction::foldUnnecessaryBitop() { return this; } -static inline bool CanProduceNegativeZero(MDefinition* def) { - // Test if this instruction can produce negative zero even when bailing out - // and changing types. - switch (def->op()) { - case MDefinition::Opcode::Constant: - if (def->type() == MIRType::Double && - def->toConstant()->toDouble() == -0.0) { - return true; - } - [[fallthrough]]; - case MDefinition::Opcode::BitAnd: - case MDefinition::Opcode::BitOr: - case MDefinition::Opcode::BitXor: - case MDefinition::Opcode::BitNot: - case MDefinition::Opcode::Lsh: - case MDefinition::Opcode::Rsh: - return false; - default: - return true; - } -} - -static inline bool NeedNegativeZeroCheck(MDefinition* def) { - if (def->isGuard() || def->isGuardRangeBailouts()) { - return true; - } - - // Test if all uses have the same semantics for -0 and 0 - for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) { - if (use->consumer()->isResumePoint()) { - return true; - } - - MDefinition* use_def = use->consumer()->toDefinition(); - switch (use_def->op()) { - case MDefinition::Opcode::Add: { - // If add is truncating -0 and 0 are observed as the same. - if (use_def->toAdd()->isTruncated()) { - break; - } - - // x + y gives -0, when both x and y are -0 - - // Figure out the order in which the addition's operands will - // execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR - // definitions for us so that this just requires comparing ids. - MDefinition* first = use_def->toAdd()->lhs(); - MDefinition* second = use_def->toAdd()->rhs(); - if (first->id() > second->id()) { - std::swap(first, second); - } - // Negative zero checks can be removed on the first executed - // operand only if it is guaranteed the second executed operand - // will produce a value other than -0. While the second is - // typed as an int32, a bailout taken between execution of the - // operands may change that type and cause a -0 to flow to the - // second. - // - // There is no way to test whether there are any bailouts - // between execution of the operands, so remove negative - // zero checks from the first only if the second's type is - // independent from type changes that may occur after bailing. - if (def == first && CanProduceNegativeZero(second)) { - return true; - } - - // The negative zero check can always be removed on the second - // executed operand; by the time this executes the first will have - // been evaluated as int32 and the addition's result cannot be -0. - break; - } - case MDefinition::Opcode::Sub: { - // If sub is truncating -0 and 0 are observed as the same - if (use_def->toSub()->isTruncated()) { - break; - } - - // x + y gives -0, when x is -0 and y is 0 - - // We can remove the negative zero check on the rhs, only if we - // are sure the lhs isn't negative zero. - - // The lhs is typed as integer (i.e. not -0.0), but it can bailout - // and change type. This should be fine if the lhs is executed - // first. However if the rhs is executed first, the lhs can bail, - // change type and become -0.0 while the rhs has already been - // optimized to not make a difference between zero and negative zero. - MDefinition* lhs = use_def->toSub()->lhs(); - MDefinition* rhs = use_def->toSub()->rhs(); - if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs)) { - return true; - } - - [[fallthrough]]; - } - case MDefinition::Opcode::StoreElement: - case MDefinition::Opcode::StoreHoleValueElement: - case MDefinition::Opcode::LoadElement: - case MDefinition::Opcode::LoadElementHole: - case MDefinition::Opcode::LoadUnboxedScalar: - case MDefinition::Opcode::LoadDataViewElement: - case MDefinition::Opcode::LoadTypedArrayElementHole: - case MDefinition::Opcode::CharCodeAt: - case MDefinition::Opcode::Mod: - case MDefinition::Opcode::InArray: - // Only allowed to remove check when definition is the second operand - if (use_def->getOperand(0) == def) { - return true; - } - for (size_t i = 2, e = use_def->numOperands(); i < e; i++) { - if (use_def->getOperand(i) == def) { - return true; - } - } - break; - case MDefinition::Opcode::BoundsCheck: - // Only allowed to remove check when definition is the first operand - if (use_def->toBoundsCheck()->getOperand(1) == def) { - return true; - } - break; - case MDefinition::Opcode::ToString: - case MDefinition::Opcode::FromCharCode: - case MDefinition::Opcode::FromCodePoint: - case MDefinition::Opcode::TableSwitch: - case MDefinition::Opcode::Compare: - case MDefinition::Opcode::BitAnd: - case MDefinition::Opcode::BitOr: - case MDefinition::Opcode::BitXor: - case MDefinition::Opcode::Abs: - case MDefinition::Opcode::TruncateToInt32: - // Always allowed to remove check. No matter which operand. - break; - case MDefinition::Opcode::StoreElementHole: - case MDefinition::Opcode::StoreTypedArrayElementHole: - case MDefinition::Opcode::PostWriteElementBarrier: - // Only allowed to remove check when definition is the third operand. - for (size_t i = 0, e = use_def->numOperands(); i < e; i++) { - if (i == 2) { - continue; - } - if (use_def->getOperand(i) == def) { - return true; - } - } - break; - default: - return true; - } - } - return false; -} - #ifdef JS_JITSPEW void MBinaryArithInstruction::printOpcode(GenericPrinter& out) const { MDefinition::printOpcode(out); @@ -3937,54 +3780,6 @@ MDefinition* MDiv::foldsTo(TempAllocator& alloc) { return this; } -void MDiv::analyzeEdgeCasesForward() { - // This is only meaningful when doing integer division. - if (type() != MIRType::Int32) { - return; - } - - MOZ_ASSERT(lhs()->type() == MIRType::Int32); - MOZ_ASSERT(rhs()->type() == MIRType::Int32); - - // Try removing divide by zero check - if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) { - canBeDivideByZero_ = false; - } - - // If lhs is a constant int != INT32_MIN, then - // negative overflow check can be skipped. - if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(INT32_MIN)) { - canBeNegativeOverflow_ = false; - } - - // If rhs is a constant int != -1, likewise. - if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(-1)) { - canBeNegativeOverflow_ = false; - } - - // If lhs is != 0, then negative zero check can be skipped. - if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(0)) { - setCanBeNegativeZero(false); - } - - // If rhs is >= 0, likewise. - if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) { - if (rhs()->toConstant()->toInt32() >= 0) { - setCanBeNegativeZero(false); - } - } -} - -void MDiv::analyzeEdgeCasesBackward() { - // In general, canBeNegativeZero_ is only valid for integer divides. - // It's fine to access here because we're only using it to avoid - // wasting effort to decide whether we can clear an already cleared - // flag. - if (canBeNegativeZero_ && !NeedNegativeZeroCheck(this)) { - setCanBeNegativeZero(false); - } -} - bool MDiv::fallible() const { return !isTruncated(); } MDefinition* MMod::foldsTo(TempAllocator& alloc) { @@ -4003,24 +3798,6 @@ MDefinition* MMod::foldsTo(TempAllocator& alloc) { return this; } -void MMod::analyzeEdgeCasesForward() { - // These optimizations make sense only for integer division - if (type() != MIRType::Int32) { - return; - } - - if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) { - canBeDivideByZero_ = false; - } - - if (rhs()->isConstant()) { - int32_t n = rhs()->toConstant()->toInt32(); - if (n > 0 && !IsPowerOfTwo(uint32_t(n))) { - canBePowerOfTwoDivisor_ = false; - } - } -} - bool MMod::fallible() const { return !isTruncated() && (isUnsigned() || canBeDivideByZero() || canBeNegativeDividend()); @@ -4126,34 +3903,6 @@ MDefinition* MMul::foldsTo(TempAllocator& alloc) { return this; } -void MMul::analyzeEdgeCasesForward() { - // Try to remove the check for negative zero - // This only makes sense when using the integer multiplication - if (type() != MIRType::Int32) { - return; - } - - // If lhs is > 0, no need for negative zero check. - if (lhs()->isConstant() && lhs()->type() == MIRType::Int32) { - if (lhs()->toConstant()->toInt32() > 0) { - setCanBeNegativeZero(false); - } - } - - // If rhs is > 0, likewise. - if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) { - if (rhs()->toConstant()->toInt32() > 0) { - setCanBeNegativeZero(false); - } - } -} - -void MMul::analyzeEdgeCasesBackward() { - if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) { - setCanBeNegativeZero(false); - } -} - bool MMul::canOverflow() const { if (isTruncated()) { return false; @@ -4699,12 +4448,6 @@ MDefinition* MBooleanToInt32::foldsTo(TempAllocator& alloc) { return this; } -void MToNumberInt32::analyzeEdgeCasesBackward() { - if (!NeedNegativeZeroCheck(this)) { - setNeedsNegativeZeroCheck(false); - } -} - MDefinition* MTruncateToInt32::foldsTo(TempAllocator& alloc) { MDefinition* input = getOperand(0); if (input->isBox()) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h @@ -678,8 +678,6 @@ class MDefinition : public MNode { bool congruentIfOperandsEqual(const MDefinition* ins) const; virtual MDefinition* foldsTo(TempAllocator& alloc); - virtual void analyzeEdgeCasesForward(); - virtual void analyzeEdgeCasesBackward(); // |canTruncate| reports if this instruction supports truncation. If // |canTruncate| function returns true, then the |truncate| function is @@ -3826,7 +3824,6 @@ class MToNumberInt32 : public MUnaryInstruction, public ToInt32Policy::Data { MDefinition* foldsTo(TempAllocator& alloc) override; // this only has backwards information flow. - void analyzeEdgeCasesBackward() override; bool needsNegativeZeroCheck() const { return needsNegativeZeroCheck_; } void setNeedsNegativeZeroCheck(bool needsCheck) { @@ -5215,8 +5212,6 @@ class MMul : public MBinaryArithInstruction { } MDefinition* foldsTo(TempAllocator& alloc) override; - void analyzeEdgeCasesForward() override; - void analyzeEdgeCasesBackward() override; void collectRangeInfoPreTrunc() override; double getIdentity() const override { return 1; } @@ -5314,8 +5309,6 @@ class MDiv : public MBinaryArithInstruction { } MDefinition* foldsTo(TempAllocator& alloc) override; - void analyzeEdgeCasesForward() override; - void analyzeEdgeCasesBackward() override; double getIdentity() const override { MOZ_CRASH("not used"); } @@ -5452,8 +5445,6 @@ class MMod : public MBinaryArithInstruction { return canBePowerOfTwoDivisor_; } - void analyzeEdgeCasesForward() override; - bool isUnsigned() const { return unsigned_; } bool trapOnError() const { return trapOnError_; } diff --git a/js/src/jit/moz.build b/js/src/jit/moz.build @@ -38,7 +38,6 @@ UNIFIED_SOURCES += [ "CompileWrappers.cpp", "Disassemble.cpp", "DominatorTree.cpp", - "EdgeCaseAnalysis.cpp", "EffectiveAddressAnalysis.cpp", "ExecutableAllocator.cpp", "FlushICache.cpp", diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp @@ -13855,16 +13855,6 @@ bool SetContextJITOptions(JSContext* cx, const OptionParser& op) { } } - if (const char* str = op.getStringOption("ion-edgecase-analysis")) { - if (strcmp(str, "on") == 0) { - jit::JitOptions.disableEdgeCaseAnalysis = false; - } else if (strcmp(str, "off") == 0) { - jit::JitOptions.disableEdgeCaseAnalysis = true; - } else { - return OptionFailure("ion-edgecase-analysis", str); - } - } - if (const char* str = op.getStringOption("ion-pruning")) { if (strcmp(str, "on") == 0) { jit::JitOptions.disablePruning = false;