Ignore:
Timestamp:
Jan 5, 2016, 3:08:58 PM (9 years ago)
Author:
[email protected]
Message:

Profiling should detect when multiplication overflows but does not create negative zero.
https://bugs.webkit.org/show_bug.cgi?id=132470

Reviewed by Geoffrey Garen.

  • assembler/MacroAssemblerARM64.h:

(JSC::MacroAssemblerARM64::or32):

  • assembler/MacroAssemblerARMv7.h:

(JSC::MacroAssemblerARMv7::or32):

  • New or32 emitter needed by the mul snippet.
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::resultProfileForBytecodeOffset):
(JSC::CodeBlock::updateResultProfileForBytecodeOffset): Deleted.

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::ensureResultProfile):
(JSC::CodeBlock::addResultProfile): Deleted.
(JSC::CodeBlock::likelyToTakeDeepestSlowCase): Deleted.

  • Added a m_bytecodeOffsetToResultProfileIndexMap because we can now add result profiles in any order (based on runtime execution), not necessarily in bytecode order at baseline compilation time.
  • bytecode/ValueProfile.cpp:

(WTF::printInternal):

  • bytecode/ValueProfile.h:

(JSC::ResultProfile::didObserveInt52Overflow):
(JSC::ResultProfile::setObservedInt52Overflow):

  • Add new Int52Overflow flags.
  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::makeSafe):

  • Now with more straightforward mapping of profiling info.
  • dfg/DFGCommon.h:
  • Fixed a typo in a comment.
  • dfg/DFGNode.h:

(JSC::DFG::Node::arithNodeFlags):
(JSC::DFG::Node::mayHaveNonIntResult):
(JSC::DFG::Node::hasConstantBuffer):

  • dfg/DFGNodeFlags.cpp:

(JSC::DFG::dumpNodeFlags):

  • dfg/DFGNodeFlags.h:

(JSC::DFG::nodeMayOverflowInt52):
(JSC::DFG::nodeCanSpeculateInt52):

  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • We now have profiling info for whether the result was ever seen to be a non-Int. Use this to make a better prediction.
  • jit/JITArithmetic.cpp:

(JSC::JIT::emit_op_div):
(JSC::JIT::emit_op_mul):

  • Switch to using CodeBlock::ensureResultProfile(). ResultProfiles can now be created at any time (including the slow path), not just in bytecode order during baseline compilation.
  • jit/JITMulGenerator.cpp:

(JSC::JITMulGenerator::generateFastPath):

  • Removed the fast path profiling code for NegZero because we'll go to the slow path anyway. Let the slow path do the profiling for us.
  • Added profiling for NegZero and potential Int52 overflows in the fast path that does double math.
  • runtime/CommonSlowPaths.cpp:

(JSC::updateResultProfileForBinaryArithOp):

  • Removed the RETURN_WITH_RESULT_PROFILING macro (2 less macros), and just use the RETURN_WITH_PROFILING macro instead with a call to updateResultProfileForBinaryArithOp(). This makes it clear what we're doing to do profiling in each case, and also allows us to do custom profiling for each opcode if needed. However, so far, we always call updateResultProfileForBinaryArithOp().
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r194294 r194613  
    136136    } while (false)
    137137
    138 #define RETURN_WITH_RESULT_PROFILING(value__) \
    139     RETURN_WITH_PROFILING(value__, PROFILE_RESULT(returnValue__))
    140    
    141 #define PROFILE_RESULT(value__) do { \
    142         CodeBlock* codeBlock = exec->codeBlock();                                   \
    143         unsigned bytecodeOffset = codeBlock->bytecodeOffset(pc);                    \
    144         codeBlock->updateResultProfileForBytecodeOffset(bytecodeOffset, value__);   \
    145     } while (false)
    146 
    147138#define CALL_END_IMPL(exec, callTarget) RETURN_TWO((callTarget), (exec))
    148139
     
    359350}
    360351
     352#if ENABLE(DFG_JIT)
     353static void updateResultProfileForBinaryArithOp(ExecState* exec, Instruction* pc, JSValue result, JSValue left, JSValue right)
     354{
     355    CodeBlock* codeBlock = exec->codeBlock();
     356    unsigned bytecodeOffset = codeBlock->bytecodeOffset(pc);
     357    ResultProfile* profile = codeBlock->ensureResultProfile(bytecodeOffset);
     358
     359    if (result.isNumber()) {
     360        if (!result.isInt32()) {
     361            if (left.isInt32() && right.isInt32())
     362                profile->setObservedInt32Overflow();
     363
     364            double doubleVal = result.asNumber();
     365            if (!doubleVal && std::signbit(doubleVal))
     366                profile->setObservedNegZeroDouble();
     367            else {
     368                profile->setObservedNonNegZeroDouble();
     369
     370                // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value.
     371                // Therefore, we will get a false positive if the result is that value. This is intentionally
     372                // done to simplify the checking algorithm.
     373                static const int64_t int52OverflowPoint = (1ll << 51);
     374                int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal));
     375                if (int64Val >= int52OverflowPoint)
     376                    profile->setObservedInt52Overflow();
     377            }
     378        }
     379    } else
     380        profile->setObservedNonNumber();
     381}
     382#else
     383static void updateResultProfileForBinaryArithOp(ExecState*, Instruction*, JSValue, JSValue, JSValue) { }
     384#endif
     385
    361386SLOW_PATH_DECL(slow_path_add)
    362387{
     
    364389    JSValue v1 = OP_C(2).jsValue();
    365390    JSValue v2 = OP_C(3).jsValue();
    366    
     391    JSValue result;
     392
    367393    if (v1.isString() && !v2.isObject())
    368         RETURN_WITH_RESULT_PROFILING(jsString(exec, asString(v1), v2.toString(exec)));
    369    
    370     if (v1.isNumber() && v2.isNumber())
    371         RETURN_WITH_RESULT_PROFILING(jsNumber(v1.asNumber() + v2.asNumber()));
    372    
    373     RETURN_WITH_RESULT_PROFILING(jsAddSlowCase(exec, v1, v2));
     394        result = jsString(exec, asString(v1), v2.toString(exec));
     395    else if (v1.isNumber() && v2.isNumber())
     396        result = jsNumber(v1.asNumber() + v2.asNumber());
     397    else
     398        result = jsAddSlowCase(exec, v1, v2);
     399
     400    RETURN_WITH_PROFILING(result, {
     401        updateResultProfileForBinaryArithOp(exec, pc, result, v1, v2);
     402    });
    374403}
    375404
     
    381410{
    382411    BEGIN();
    383     double a = OP_C(2).jsValue().toNumber(exec);
    384     double b = OP_C(3).jsValue().toNumber(exec);
    385     RETURN_WITH_RESULT_PROFILING(jsNumber(a * b));
     412    JSValue left = OP_C(2).jsValue();
     413    JSValue right = OP_C(3).jsValue();
     414    double a = left.toNumber(exec);
     415    double b = right.toNumber(exec);
     416    JSValue result = jsNumber(a * b);
     417    RETURN_WITH_PROFILING(result, {
     418        updateResultProfileForBinaryArithOp(exec, pc, result, left, right);
     419    });
    386420}
    387421
     
    389423{
    390424    BEGIN();
    391     double a = OP_C(2).jsValue().toNumber(exec);
    392     double b = OP_C(3).jsValue().toNumber(exec);
    393     RETURN_WITH_RESULT_PROFILING(jsNumber(a - b));
     425    JSValue left = OP_C(2).jsValue();
     426    JSValue right = OP_C(3).jsValue();
     427    double a = left.toNumber(exec);
     428    double b = right.toNumber(exec);
     429    JSValue result = jsNumber(a - b);
     430    RETURN_WITH_PROFILING(result, {
     431        updateResultProfileForBinaryArithOp(exec, pc, result, left, right);
     432    });
    394433}
    395434
     
    397436{
    398437    BEGIN();
    399     double a = OP_C(2).jsValue().toNumber(exec);
    400     double b = OP_C(3).jsValue().toNumber(exec);
    401     RETURN_WITH_RESULT_PROFILING(jsNumber(a / b));
     438    JSValue left = OP_C(2).jsValue();
     439    JSValue right = OP_C(3).jsValue();
     440    double a = left.toNumber(exec);
     441    double b = right.toNumber(exec);
     442    JSValue result = jsNumber(a / b);
     443    RETURN_WITH_PROFILING(result, {
     444        updateResultProfileForBinaryArithOp(exec, pc, result, left, right);
     445    });
    402446}
    403447
Note: See TracChangeset for help on using the changeset viewer.