Ignore:
Timestamp:
Dec 10, 2016, 1:04:05 PM (9 years ago)
Author:
[email protected]
Message:

REGRESSION(r209653) Crash in CallFrameShuffler::snapshot()
https://bugs.webkit.org/show_bug.cgi?id=165728

Reviewed by Filip Pizlo.

JSTests:

New regression test.

  • stress/regress-165728.js: Added.

(sum1):
(sum2):
(tailCaller):
(test):

Source/JavaScriptCore:

It can be the case that a JSValueReg's CachedRecovery is the source for mutliple
GPRs. We only store the CachedRecovery in one slot of m_newRegisters to simplify
the recovery process. This is also done for the case where the recovery source
and destination are the same GPR.

In light of this change, snapshot needs to be taught that one CacheRecovery is
the source for multiple registers. This is done by using a two step process.
First find all the argument CachedRecovery's and create a vector mapping all of
the target GPRs and the source recovery. Then use that vector to get the
recovery for each register.

  • jit/CallFrameShuffler.h:

(JSC::CallFrameShuffler::snapshot):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h

    r209653 r209673  
    114114        }
    115115        data.args.resize(argCount());
     116
     117        Vector<ValueRecovery> registerArgRecoveries;
     118#if USE(JSVALUE64)
     119        // Find cached recoveries for all argument registers.
     120        // We do this here, because a cached recovery may be the source for multiple
     121        // argument registers, but it is only stored in one m_newRegister index.
     122        if (data.argumentsInRegisters) {
     123            unsigned maxArgumentRegister = std::min(static_cast<unsigned>(argCount()), NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS);
     124            registerArgRecoveries.resize(maxArgumentRegister);
     125            for (size_t i = 0; i < maxArgumentRegister; ++i) {
     126                Reg reg { argumentRegisterForFunctionArgument(i) };
     127                CachedRecovery* cachedRecovery { m_newRegisters[reg] };
     128                if (cachedRecovery) {
     129                    for (auto jsValueReg : cachedRecovery->gprTargets())
     130                        registerArgRecoveries[jsFunctionArgumentForArgumentRegister(jsValueReg.gpr())] = cachedRecovery->recovery();
     131                }
     132            }
     133        }
     134#endif
     135       
    116136        for (size_t i = 0; i < argCount(); ++i) {
    117137            if (argumentsLocation == StackArgs || i >= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
     
    119139            else {
    120140                Reg reg { argumentRegisterForFunctionArgument(i) };
    121                 CachedRecovery* cachedRecovery { m_newRegisters[reg] };
    122                 data.args[i] = cachedRecovery->recovery();
     141                ASSERT(registerArgRecoveries[i]);
     142                data.args[i] = registerArgRecoveries[i];
    123143            }
    124144        }
     
    441461#endif
    442462
    443     // This stores, for each register, information about the recovery
    444     // for the value that should eventually go into that register. The
    445     // only registers that have a target recovery will be callee-save
    446     // registers, as well as possibly one JSValueRegs for holding the
    447     // callee.
     463    // This stores information about the recovery for the value that
     464    // should eventually go into that register. In some cases there
     465    // are recoveries that have multiple targets. For those recoveries,
     466    // only the first target register in the map has the recovery.
     467    // We optimize the case where there are multiple targets for one
     468    // recovery where one of those targets is also the source register.
     469    // Restoring the first target becomes a nop and simplifies the logic
     470    // of restoring the remaining targets.
    448471    //
    449472    // Once the correct value has been put into the registers, and
    450473    // contrary to what we do with m_newFrame, we keep the entry in
    451474    // m_newRegisters to simplify spilling.
     475    //
     476    // If a recovery has multiple target registers, we copy the value
     477    // from the first target register to the remaining target registers
     478    // at the end of the shuffling process.
    452479    RegisterMap<CachedRecovery*> m_newRegisters;
    453480
Note: See TracChangeset for help on using the changeset viewer.