tor-browser

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

commit 310a64d8d88232c185f2ba07b89450fbbd230769
parent 48c7b2c166a4209ef64fe57f9fa97cba6aee0ce0
Author: agoloman <agoloman@mozilla.com>
Date:   Wed, 12 Nov 2025 21:01:00 +0200

Revert "Bug 1966196 - Expand EnvironmentCoordinate hops bitwidth to 16 r=nbp" for causing spidermonkey bustages.

This reverts commit f0c591856b1421d38a70231f3912c494309689e4.

Diffstat:
Mjs/src/frontend/BytecodeEmitter.cpp | 6+++---
Mjs/src/frontend/EmitterScope.cpp | 6+++---
Mjs/src/frontend/EmitterScope.h | 2+-
Mjs/src/frontend/NameAnalysisTypes.h | 12++++++------
Mjs/src/frontend/Stencil.cpp | 6+++---
Mjs/src/jit-test/tests/class/super-in-nested-eval.js | 9+++++----
Mjs/src/jit-test/tests/debug/breakpoint-dot-generator.js | 4++--
Mjs/src/jit-test/tests/debug/bug1368736.js | 2+-
Djs/src/jit-test/tests/environments/bug1966196.js | 10----------
Mjs/src/jit/BaselineCodeGen.cpp | 10+++++-----
Mjs/src/vm/BytecodeLocation.h | 4++--
Mjs/src/vm/BytecodeUtil.h | 20++++++++++----------
Mjs/src/vm/Interpreter.cpp | 2+-
Mjs/src/vm/Opcodes.h | 24++++++++++++------------
Mjs/src/vm/PortableBaselineInterpret.cpp | 2+-
15 files changed, 55 insertions(+), 64 deletions(-)

diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp @@ -1435,12 +1435,12 @@ bool BytecodeEmitter::emitThisEnvironmentCallee() { size_t numHops = countThisEnvironmentHops(); static_assert( - ENVCOORD_HOPS_LIMIT - 1 <= UINT16_MAX, + ENVCOORD_HOPS_LIMIT - 1 <= UINT8_MAX, "JSOp::EnvCallee operand size should match ENVCOORD_HOPS_LIMIT"); MOZ_ASSERT(numHops < ENVCOORD_HOPS_LIMIT - 1); - return emitUint16Operand(JSOp::EnvCallee, numHops); + return emit2(JSOp::EnvCallee, numHops); } bool BytecodeEmitter::emitSuperBase() { @@ -2206,7 +2206,7 @@ bool BytecodeEmitter::emitSetThis(BinaryNode* setThisNode) { lexicalLoc = NameLocation::FrameSlot(BindingKind::Let, loc.frameSlot()); } else if (loc.kind() == NameLocation::Kind::EnvironmentCoordinate) { EnvironmentCoordinate coord = loc.environmentCoordinate(); - uint16_t hops = AssertedCast<uint16_t>(coord.hops()); + uint8_t hops = AssertedCast<uint8_t>(coord.hops()); lexicalLoc = NameLocation::EnvironmentCoordinate(BindingKind::Let, hops, coord.slot()); } else { diff --git a/js/src/frontend/EmitterScope.cpp b/js/src/frontend/EmitterScope.cpp @@ -69,7 +69,7 @@ bool EmitterScope::checkEnvironmentChainLength(BytecodeEmitter* bce) { return false; } - environmentChainLength_ = mozilla::AssertedCast<uint16_t>(hops + 1); + environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1); return true; } @@ -147,7 +147,7 @@ bool EmitterScope::nameCanBeFree(BytecodeEmitter* bce, NameLocation EmitterScope::searchAndCache(BytecodeEmitter* bce, TaggedParserAtomIndex name) { Maybe<NameLocation> loc; - uint16_t hops = hasEnvironment() ? 1 : 0; + uint8_t hops = hasEnvironment() ? 1 : 0; DebugOnly<bool> inCurrentScript = enclosingInFrame(); // Start searching in the current compilation. @@ -1169,7 +1169,7 @@ Maybe<NameLocation> EmitterScope::locationBoundInScope( TaggedParserAtomIndex name, EmitterScope* target) { // The target scope must be an intra-frame enclosing scope of this // one. Count the number of extra hops to reach it. - uint16_t extraHops = 0; + uint8_t extraHops = 0; for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) { if (es->hasEnvironment()) { extraHops++; diff --git a/js/src/frontend/EmitterScope.h b/js/src/frontend/EmitterScope.h @@ -57,7 +57,7 @@ class MOZ_STACK_CLASS EmitterScope : public Nestable<EmitterScope> { #endif // The number of enclosing environments. Used for error checking. - uint16_t environmentChainLength_; + uint8_t environmentChainLength_; // The next usable slot on the frame for not-closed over bindings. // diff --git a/js/src/frontend/NameAnalysisTypes.h b/js/src/frontend/NameAnalysisTypes.h @@ -280,8 +280,8 @@ class NameLocation { // If the name is closed over and accessed via EnvironmentCoordinate, the // number of dynamic environments to skip. // - // Otherwise UINT16_MAX. - uint16_t hops_; + // Otherwise UINT8_MAX. + uint8_t hops_; // If the name lives on the frame, the slot frame. // @@ -294,7 +294,7 @@ class NameLocation { static_assert(LOCALNO_BITS == ENVCOORD_SLOT_BITS, "Frame and environment slots must be same sized."); - NameLocation(Kind kind, BindingKind bindingKind, uint16_t hops = UINT16_MAX, + NameLocation(Kind kind, BindingKind bindingKind, uint8_t hops = UINT8_MAX, uint32_t slot = 0) : kind_(kind), bindingKind_(bindingKind), hops_(hops), slot_(slot) {} @@ -330,13 +330,13 @@ class NameLocation { return NameLocation(Kind::FrameSlot, bindKind, 0, slot); } - static NameLocation EnvironmentCoordinate(BindingKind bindKind, uint16_t hops, + static NameLocation EnvironmentCoordinate(BindingKind bindKind, uint8_t hops, uint32_t slot) { MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT); return NameLocation(Kind::EnvironmentCoordinate, bindKind, hops, slot); } static NameLocation DebugEnvironmentCoordinate(BindingKind bindKind, - uint16_t hops, uint32_t slot) { + uint8_t hops, uint32_t slot) { MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT); return NameLocation(Kind::DebugEnvironmentCoordinate, bindKind, hops, slot); } @@ -368,7 +368,7 @@ class NameLocation { return slot_; } - NameLocation addHops(uint16_t more) { + NameLocation addHops(uint8_t more) { MOZ_ASSERT(hops_ < ENVCOORD_HOPS_LIMIT - more); MOZ_ASSERT(kind_ == Kind::EnvironmentCoordinate); return NameLocation(kind_, bindingKind_, hops_ + more, slot_); diff --git a/js/src/frontend/Stencil.cpp b/js/src/frontend/Stencil.cpp @@ -1151,7 +1151,7 @@ NameLocation ScopeContext::searchInEnclosingScopeWithCache( mozilla::Maybe<NameLocation> found; // Number of enclosing scope we walked over. - uint16_t hops = 0; + uint8_t hops = 0; for (InputScopeIter si(input.enclosingScope); si; si++) { MOZ_ASSERT(NameIsOnEnvironment(fc, parserAtoms, input.atomCache, si.scope(), @@ -1220,8 +1220,8 @@ NameLocation ScopeContext::searchInEnclosingScopeNoCache( // NameLocation which contains relative locations to access `name`. mozilla::Maybe<NameLocation> result; - // Number of enclosing scope we walked over. - uint16_t hops = 0; + // Number of enclosing scoep we walked over. + uint8_t hops = 0; for (InputScopeIter si(input.enclosingScope); si; si++) { MOZ_ASSERT(NameIsOnEnvironment(fc, parserAtoms, input.atomCache, si.scope(), diff --git a/js/src/jit-test/tests/class/super-in-nested-eval.js b/js/src/jit-test/tests/class/super-in-nested-eval.js @@ -15,18 +15,19 @@ class D extends C { } } +const MAX_DEPTH = 250; + // These values should work. -var depths = [0, 1, 10, 200, 300]; +var depths = [0, 1, 10, 200, MAX_DEPTH]; for (var d of depths) { var o = new D(d); assertEq(o.x, d + 1); } -// When we use a large enough depth that we run out of stack, we throw instead -// of crashing +// This should fail. var ex; try { - new D(2000); + new D(MAX_DEPTH + 1); } catch(e) { ex = e; } diff --git a/js/src/jit-test/tests/debug/breakpoint-dot-generator.js b/js/src/jit-test/tests/debug/breakpoint-dot-generator.js @@ -12,7 +12,7 @@ const script = dg.makeDebuggeeValue(g.func).script; // // 00000: Generator # GENERATOR // 00001: SetAliasedVar ".generator" # GENERATOR -// 00007: InitialYield 0 # RVAL GENERATOR RESUMEKIND +// 00006: InitialYield 0 # RVAL GENERATOR RESUMEKIND // Setting a breakpoint at `SetAliasedVar ".generator"` should be disallow. let caught = false; @@ -27,7 +27,7 @@ assertEq(caught, true); // Setting breakpoints to other opcodes should be allowed. script.setBreakpoint(0, {}); -script.setBreakpoint(7, {}); +script.setBreakpoint(6, {}); // Offset 1 shouldn't be exposed. assertEq(script.getPossibleBreakpoints().some(p => p.offset == 1), false); diff --git a/js/src/jit-test/tests/debug/bug1368736.js b/js/src/jit-test/tests/debug/bug1368736.js @@ -2,7 +2,7 @@ g = newGlobal({newCompartment: true}); hits = 0; Debugger(g).onDebuggerStatement = function(frame) { // Set a breakpoint at the JSOP_AFTERYIELD op. - frame.script.setBreakpoint(128, {hit: function() { hits++; }}); + frame.script.setBreakpoint(120, {hit: function() { hits++; }}); } g.eval(` function* range() { diff --git a/js/src/jit-test/tests/environments/bug1966196.js b/js/src/jit-test/tests/environments/bug1966196.js @@ -1,10 +0,0 @@ -// |jit-test| - -let REPEAT_COUNT = 300; -let someCondition = Math.random() > 0.5; -function generateJS() { - let str = "if (someCondition) {let foo;".repeat(REPEAT_COUNT) + - "}".repeat(REPEAT_COUNT); - return str; -} -eval(generateJS()); diff --git a/js/src/jit/BaselineCodeGen.cpp b/js/src/jit/BaselineCodeGen.cpp @@ -3907,9 +3907,9 @@ Address BaselineCodeGen<Handler>::getEnvironmentCoordinateAddress( // number of environment objects. static void LoadAliasedVarEnv(MacroAssembler& masm, Register env, Register scratch) { - static_assert(ENVCOORD_HOPS_LEN == 2, - "Code assumes number of hops is stored in uint16 operand"); - LoadUint16Operand(masm, scratch); + static_assert(ENVCOORD_HOPS_LEN == 1, + "Code assumes number of hops is stored in uint8 operand"); + LoadUint8Operand(masm, scratch); Label top, done; masm.branchTest32(Assembler::Zero, scratch, scratch, &done); @@ -5918,7 +5918,7 @@ bool BaselineCodeGen<Handler>::emit_Callee() { template <> bool BaselineCompilerCodeGen::emit_EnvCallee() { frame.syncStack(0); - uint16_t numHops = GET_ENVCOORD_HOPS(handler.pc()); + uint8_t numHops = GET_UINT8(handler.pc()); Register scratch = R0.scratchReg(); masm.loadPtr(frame.addressOfEnvironmentChain(), scratch); @@ -5939,7 +5939,7 @@ bool BaselineInterpreterCodeGen::emit_EnvCallee() { Register env = R1.scratchReg(); static_assert(JSOpLength_EnvCallee - sizeof(jsbytecode) == ENVCOORD_HOPS_LEN, - "op must have uint16 operand for LoadAliasedVarEnv"); + "op must have uint8 operand for LoadAliasedVarEnv"); // Load the right environment object. masm.loadPtr(frame.addressOfEnvironmentChain(), env); diff --git a/js/src/vm/BytecodeLocation.h b/js/src/vm/BytecodeLocation.h @@ -10,7 +10,7 @@ #include "frontend/NameAnalysisTypes.h" #include "js/TypeDecls.h" #include "vm/BuiltinObjectKind.h" -#include "vm/BytecodeUtil.h" // GET_ENVCOORD_HOPS +#include "vm/BytecodeUtil.h" #include "vm/CheckIsObjectKind.h" // CheckIsObjectKind #include "vm/CompletionKind.h" // CompletionKind #include "vm/ConstantCompareOperand.h" // ConstantCompareOperand @@ -261,7 +261,7 @@ class BytecodeLocation { uint32_t getEnvCalleeNumHops() const { MOZ_ASSERT(is(JSOp::EnvCallee)); - return GET_ENVCOORD_HOPS(rawBytecode_); + return GET_UINT8(rawBytecode_); } EnvironmentCoordinate getEnvironmentCoordinate() const { diff --git a/js/src/vm/BytecodeUtil.h b/js/src/vm/BytecodeUtil.h @@ -235,23 +235,23 @@ static inline bool IsBackedgeForLoopHead(jsbytecode* pc, jsbytecode* loopHead) { /* * Describes the 'hops' component of a JOF_ENVCOORD opcode. * - * Note: this component is only 16 bits wide, limiting the maximum number of - * scopes between a use and def to roughly 65535. This is a pretty small limit - * but note that SpiderMonkey's recursive descent parser can't parse too many - * functions before hitting the C-stack recursion limit so this shouldn't + * Note: this component is only 8 bits wide, limiting the maximum number of + * scopes between a use and def to roughly 255. This is a pretty small limit but + * note that SpiderMonkey's recursive descent parser can only parse about this + * many functions before hitting the C-stack recursion limit so this shouldn't * be a significant limitation in practice. */ -static inline uint16_t GET_ENVCOORD_HOPS(jsbytecode* pc) { - return GET_UINT16(pc); +static inline uint8_t GET_ENVCOORD_HOPS(jsbytecode* pc) { + return GET_UINT8(pc); } -static inline void SET_ENVCOORD_HOPS(jsbytecode* pc, uint16_t hops) { - SET_UINT16(pc, hops); +static inline void SET_ENVCOORD_HOPS(jsbytecode* pc, uint8_t hops) { + SET_UINT8(pc, hops); } -static const unsigned ENVCOORD_HOPS_LEN = 2; -static const unsigned ENVCOORD_HOPS_BITS = 16; +static const unsigned ENVCOORD_HOPS_LEN = 1; +static const unsigned ENVCOORD_HOPS_BITS = 8; static const unsigned ENVCOORD_HOPS_LIMIT = 1 << ENVCOORD_HOPS_BITS; /* Describes the 'slot' component of a JOF_ENVCOORD opcode. */ diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp @@ -4390,7 +4390,7 @@ bool MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER js::Interpret(JSContext* cx, END_CASE(DynamicImport) CASE(EnvCallee) { - uint16_t numHops = GET_ENVCOORD_HOPS(REGS.pc); + uint8_t numHops = GET_UINT8(REGS.pc); JSObject* env = &REGS.fp()->environmentChain()->as<EnvironmentObject>(); for (unsigned i = 0; i < numHops; i++) { env = &env->as<EnvironmentObject>().enclosingEnvironment(); diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h @@ -2726,10 +2726,10 @@ * * Category: Variables and scopes * Type: Initialization - * Operands: uint16_t hops, uint24_t slot + * Operands: uint8_t hops, uint24_t slot * Stack: v => v */ \ - MACRO(InitAliasedLexical, init_aliased_lexical, NULL, 6, 1, 1, JOF_ENVCOORD|JOF_PROPINIT) \ + MACRO(InitAliasedLexical, init_aliased_lexical, NULL, 5, 1, 1, JOF_ENVCOORD|JOF_PROPINIT) \ /* * Throw a ReferenceError if the value on top of the stack is uninitialized. * @@ -2758,10 +2758,10 @@ * * Category: Variables and scopes * Type: Initialization - * Operands: uint16_t hops, uint24_t slot + * Operands: uint8_t hops, uint24_t slot * Stack: v => v */ \ - MACRO(CheckAliasedLexical, check_aliased_lexical, NULL, 6, 1, 1, JOF_ENVCOORD) \ + MACRO(CheckAliasedLexical, check_aliased_lexical, NULL, 5, 1, 1, JOF_ENVCOORD) \ /* * Throw a ReferenceError if the value on top of the stack is * `MagicValue(JS_UNINITIALIZED_LEXICAL)`. Used in derived class @@ -2937,20 +2937,20 @@ * * Category: Variables and scopes * Type: Getting binding values - * Operands: uint16_t hops, uint24_t slot + * Operands: uint8_t hops, uint24_t slot * Stack: => aliasedVar */ \ - MACRO(GetAliasedVar, get_aliased_var, NULL, 6, 0, 1, JOF_ENVCOORD|JOF_USES_ENV) \ + MACRO(GetAliasedVar, get_aliased_var, NULL, 5, 0, 1, JOF_ENVCOORD|JOF_USES_ENV) \ /* * Push the value of an aliased binding, which may have to bypass a DebugEnvironmentProxy * on the environment chain. * * Category: Variables and scopes * Type: Getting binding values - * Operands: uint16_t hops, uint24_t slot + * Operands: uint8_t hops, uint24_t slot * Stack: => aliasedVar */ \ - MACRO(GetAliasedDebugVar, get_aliased_debug_var, NULL, 6, 0, 1, JOF_DEBUGCOORD) \ + MACRO(GetAliasedDebugVar, get_aliased_debug_var, NULL, 5, 0, 1, JOF_DEBUGCOORD) \ /* * Get the value of a module import by name and pushes it onto the stack. * @@ -3029,10 +3029,10 @@ * * Category: Variables and scopes * Type: Getting binding values - * Operands: uint16_t numHops + * Operands: uint8_t numHops * Stack: => callee */ \ - MACRO(EnvCallee, env_callee, NULL, 3, 0, 1, JOF_UINT16) \ + MACRO(EnvCallee, env_callee, NULL, 2, 0, 1, JOF_UINT8) \ /* * Assign `val` to the binding in `env` with the name given by `nameIndex`. * Throw a ReferenceError if the binding is an uninitialized lexical. @@ -3126,10 +3126,10 @@ * * Category: Variables and scopes * Type: Setting binding values - * Operands: uint16_t hops, uint24_t slot + * Operands: uint8_t hops, uint24_t slot * Stack: val => val */ \ - MACRO(SetAliasedVar, set_aliased_var, NULL, 6, 1, 1, JOF_ENVCOORD|JOF_PROPSET|JOF_USES_ENV) \ + MACRO(SetAliasedVar, set_aliased_var, NULL, 5, 1, 1, JOF_ENVCOORD|JOF_PROPSET|JOF_USES_ENV) \ /* * Assign to an intrinsic. * diff --git a/js/src/vm/PortableBaselineInterpret.cpp b/js/src/vm/PortableBaselineInterpret.cpp @@ -8677,7 +8677,7 @@ PBIResult PortableBaselineInterpret( } CASE(EnvCallee) { - uint16_t numHops = GET_ENVCOORD_HOPS(pc); + uint8_t numHops = GET_UINT8(pc); JSObject* env = &frame->environmentChain()->as<EnvironmentObject>(); for (unsigned i = 0; i < numHops; i++) { env = &env->as<EnvironmentObject>().enclosingEnvironment();