source: webkit/trunk/Source/JavaScriptCore/jit/JITNegGenerator.cpp

Last change on this file was 252422, checked in by [email protected], 6 years ago

Split ArithProfile into a Unary and a Binary version
https://bugs.webkit.org/show_bug.cgi?id=202832
<rdar://problem/56266847>

Reviewed by Keith Miller.

JSTests:

The new test (kindly provided by Mark Lam) catches the metadata corruption that used to happen in the previous version of this patch.

  • stress/regress-57020338.js: Added.

Source/JavaScriptCore:

ArithProfile was for a long time only used for add/sub/mul/div, but recently it started being used for negate. And it will soon also have to be used for inc and dec due to BigInt.
So in this patch I make a separate version that only has the data for a single argument, and thus takes half as much memory.

After discussing this change with Phil I realized that the ResultType(s) that were taking space in ArithProfile are not needed: they never change and a copy is already in the bytecode instruction itself.
Removing them allowed shrinking both kinds of ArithProfile to fit in 16 bits (9 and 13 respectively).
I kept the two kinds separate because they may shrink or grow independently in the future.

This also required adding the "orh" instruction to the offline assembler, to set bits in the ArithProfile.
This in turn motivated the addition of "storeh", as on RISC platforms "orh" on a memory location is actually loadh -> orh -> storeh.

Finally it required adding support for or16(TrustedImm32, AbsoluteAddress) in the MacroAssembler for the ICs.
Instead of directly calling it (like we used to do with or32), I introduced ArithProfile::emitUnconditionalSet, so that if either ArithProfile ever changes in size again we'll have fewer places to change.

  • assembler/MacroAssemblerARM64.h:

(JSC::MacroAssemblerARM64::or16):

  • assembler/MacroAssemblerARMv7.h:

(JSC::MacroAssemblerARMv7::or16):

  • assembler/MacroAssemblerMIPS.h:

(JSC::MacroAssemblerMIPS::or16):

  • assembler/MacroAssemblerX86.h:

(JSC::MacroAssemblerX86::or16):

  • assembler/MacroAssemblerX86_64.h:

(JSC::MacroAssemblerX86_64::or16):

  • assembler/testmasm.cpp:

(JSC::testOrImmMem):
(JSC::run):

  • bytecode/ArithProfile.cpp:

(JSC::ArithProfile<BitfieldType>::emitObserveResult):
(JSC::ArithProfile<BitfieldType>::shouldEmitSetDouble const):
(JSC::ArithProfile<BitfieldType>::emitSetDouble const):
(JSC::ArithProfile<BitfieldType>::shouldEmitSetNonNumeric const):
(JSC::ArithProfile<BitfieldType>::emitSetNonNumeric const):
(JSC::ArithProfile<BitfieldType>::shouldEmitSetBigInt const):
(JSC::ArithProfile<BitfieldType>::emitSetBigInt const):
(JSC::ArithProfile<BitfieldType>::emitUnconditionalSet const):
(WTF::printInternal):

  • bytecode/ArithProfile.h:

(JSC::ArithProfile::didObserveNonInt32 const):
(JSC::ArithProfile::didObserveDouble const):
(JSC::ArithProfile::didObserveNonNegZeroDouble const):
(JSC::ArithProfile::didObserveNegZeroDouble const):
(JSC::ArithProfile::didObserveNonNumeric const):
(JSC::ArithProfile::didObserveBigInt const):
(JSC::ArithProfile::didObserveInt32Overflow const):
(JSC::ArithProfile::didObserveInt52Overflow const):
(JSC::ArithProfile::setObservedNonNegZeroDouble):
(JSC::ArithProfile::setObservedNegZeroDouble):
(JSC::ArithProfile::setObservedNonNumeric):
(JSC::ArithProfile::setObservedBigInt):
(JSC::ArithProfile::setObservedInt32Overflow):
(JSC::ArithProfile::setObservedInt52Overflow):
(JSC::ArithProfile::observeResult):
(JSC::ArithProfile::addressOfBits const):
(JSC::ArithProfile::bits const):
(JSC::ArithProfile::ArithProfile):
(JSC::ArithProfile::hasBits const):
(JSC::ArithProfile::setBit):
(JSC::UnaryArithProfile::UnaryArithProfile):
(JSC::UnaryArithProfile::observedIntBits):
(JSC::UnaryArithProfile::observedNumberBits):
(JSC::UnaryArithProfile::argObservedType const):
(JSC::UnaryArithProfile::setArgObservedType):
(JSC::UnaryArithProfile::argSawInt32):
(JSC::UnaryArithProfile::argSawNumber):
(JSC::UnaryArithProfile::argSawNonNumber):
(JSC::UnaryArithProfile::observeArg):
(JSC::UnaryArithProfile::isObservedTypeEmpty):
(JSC::BinaryArithProfile::BinaryArithProfile):
(JSC::BinaryArithProfile::observedIntIntBits):
(JSC::BinaryArithProfile::observedNumberIntBits):
(JSC::BinaryArithProfile::observedIntNumberBits):
(JSC::BinaryArithProfile::observedNumberNumberBits):
(JSC::BinaryArithProfile::setLhsObservedType):
(JSC::BinaryArithProfile::setRhsObservedType):
(JSC::BinaryArithProfile::observeLHS):
(JSC::BinaryArithProfile::observeLHSAndRHS):
(JSC::BinaryArithProfile::isObservedTypeEmpty):

  • bytecode/BytecodeList.rb:
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::addJITAddIC):
(JSC::CodeBlock::addJITMulIC):
(JSC::CodeBlock::addJITSubIC):
(JSC::CodeBlock::addJITNegIC):
(JSC::CodeBlock::binaryArithProfileForBytecodeIndex):
(JSC::CodeBlock::unaryArithProfileForBytecodeIndex):
(JSC::CodeBlock::binaryArithProfileForPC):
(JSC::CodeBlock::unaryArithProfileForPC):
(JSC::CodeBlock::couldTakeSpecialArithFastCase):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::addMathIC):

  • bytecode/Fits.h:
  • bytecode/MethodOfGettingAValueProfile.cpp:

(JSC::MethodOfGettingAValueProfile::emitReportValue const):
(JSC::MethodOfGettingAValueProfile::reportValue):

  • bytecode/MethodOfGettingAValueProfile.h:

(JSC::MethodOfGettingAValueProfile::MethodOfGettingAValueProfile):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitUnaryOp):

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::UnaryOpNode::emitBytecode):

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::methodOfGettingAValueProfileFor):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileValueAdd):
(JSC::DFG::SpeculativeJIT::compileValueSub):
(JSC::DFG::SpeculativeJIT::compileValueNegate):
(JSC::DFG::SpeculativeJIT::compileValueMul):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileValueAdd):
(JSC::FTL::DFG::LowerDFGToB3::compileValueSub):
(JSC::FTL::DFG::LowerDFGToB3::compileValueMul):
(JSC::FTL::DFG::LowerDFGToB3::compileUnaryMathIC):
(JSC::FTL::DFG::LowerDFGToB3::compileBinaryMathIC):
(JSC::FTL::DFG::LowerDFGToB3::compileArithAddOrSub):
(JSC::FTL::DFG::LowerDFGToB3::compileValueNegate):

  • jit/JIT.h:
  • jit/JITAddGenerator.cpp:

(JSC::JITAddGenerator::generateInline):
(JSC::JITAddGenerator::generateFastPath):

  • jit/JITAddGenerator.h:
  • jit/JITArithmetic.cpp:

(JSC::JIT::emit_op_negate):
(JSC::JIT::emit_op_add):
(JSC::JIT::emitMathICFast):
(JSC::JIT::emitMathICSlow):
(JSC::JIT::emit_op_div):
(JSC::JIT::emit_op_mul):
(JSC::JIT::emit_op_sub):

  • jit/JITDivGenerator.cpp:

(JSC::JITDivGenerator::generateFastPath):

  • jit/JITDivGenerator.h:

(JSC::JITDivGenerator::JITDivGenerator):

  • jit/JITInlines.h:

(JSC::JIT::copiedArithProfile):

  • jit/JITMathIC.h:

(JSC::JITMathIC::JITMathIC):
(JSC::JITMathIC::generateInline):
(JSC::JITMathIC::arithProfile const):
(JSC::JITBinaryMathIC::JITBinaryMathIC):
(JSC::JITUnaryMathIC::JITUnaryMathIC):

  • jit/JITMulGenerator.cpp:

(JSC::JITMulGenerator::generateInline):
(JSC::JITMulGenerator::generateFastPath):

  • jit/JITMulGenerator.h:
  • jit/JITNegGenerator.cpp:

(JSC::JITNegGenerator::generateInline):
(JSC::JITNegGenerator::generateFastPath):

  • jit/JITNegGenerator.h:
  • jit/JITOperations.cpp:
  • jit/JITOperations.h:
  • jit/JITSubGenerator.cpp:

(JSC::JITSubGenerator::generateInline):
(JSC::JITSubGenerator::generateFastPath):

  • jit/JITSubGenerator.h:
  • llint/LLIntData.cpp:

(JSC::LLInt::Data::performAssertions):

  • llint/LLIntOffsetsExtractor.cpp:

(JSC::LLIntOffsetsExtractor::dummy):

  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • offlineasm/arm.rb:
  • offlineasm/arm64.rb:
  • offlineasm/cloop.rb:
  • offlineasm/instructions.rb:
  • offlineasm/mips.rb:
  • offlineasm/risc.rb:
  • offlineasm/x86.rb:
  • parser/ResultType.h:

(JSC::ResultType::ResultType):

  • runtime/CommonSlowPaths.cpp:

(JSC::updateArithProfileForUnaryArithOp):
(JSC::updateArithProfileForBinaryArithOp):
(JSC::SLOW_PATH_DECL):

File size: 5.3 KB
Line 
1/*
2 * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JITNegGenerator.h"
28
29#include "ArithProfile.h"
30
31#if ENABLE(JIT)
32
33namespace JSC {
34
35JITMathICInlineResult JITNegGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state, const UnaryArithProfile* arithProfile)
36{
37 ASSERT(m_scratchGPR != InvalidGPRReg);
38 ASSERT(m_scratchGPR != m_src.payloadGPR());
39 ASSERT(m_scratchGPR != m_result.payloadGPR());
40#if USE(JSVALUE32_64)
41 ASSERT(m_scratchGPR != m_src.tagGPR());
42 ASSERT(m_scratchGPR != m_result.tagGPR());
43#endif
44
45 // We default to speculating int32.
46 ObservedType observedTypes = ObservedType().withInt32();
47 if (arithProfile)
48 observedTypes = arithProfile->argObservedType();
49 ASSERT_WITH_MESSAGE(!observedTypes.isEmpty(), "We should not attempt to generate anything if we do not have a profile.");
50
51 if (observedTypes.isOnlyNonNumber())
52 return JITMathICInlineResult::DontGenerate;
53
54 if (observedTypes.isOnlyInt32()) {
55 jit.moveValueRegs(m_src, m_result);
56 state.slowPathJumps.append(jit.branchIfNotInt32(m_src));
57 state.slowPathJumps.append(jit.branchTest32(CCallHelpers::Zero, m_src.payloadGPR(), CCallHelpers::TrustedImm32(0x7fffffff)));
58 jit.neg32(m_result.payloadGPR());
59#if USE(JSVALUE64)
60 jit.boxInt32(m_result.payloadGPR(), m_result);
61#endif
62
63 return JITMathICInlineResult::GeneratedFastPath;
64 }
65 if (observedTypes.isOnlyNumber()) {
66 state.slowPathJumps.append(jit.branchIfInt32(m_src));
67 state.slowPathJumps.append(jit.branchIfNotNumber(m_src, m_scratchGPR));
68#if USE(JSVALUE64)
69 if (m_src.payloadGPR() != m_result.payloadGPR()) {
70 jit.move(CCallHelpers::TrustedImm64(static_cast<int64_t>(1ull << 63)), m_result.payloadGPR());
71 jit.xor64(m_src.payloadGPR(), m_result.payloadGPR());
72 } else {
73 jit.move(CCallHelpers::TrustedImm64(static_cast<int64_t>(1ull << 63)), m_scratchGPR);
74 jit.xor64(m_scratchGPR, m_result.payloadGPR());
75 }
76#else
77 jit.moveValueRegs(m_src, m_result);
78 jit.xor32(CCallHelpers::TrustedImm32(1 << 31), m_result.tagGPR());
79#endif
80 return JITMathICInlineResult::GeneratedFastPath;
81 }
82 return JITMathICInlineResult::GenerateFullSnippet;
83}
84
85bool JITNegGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const UnaryArithProfile* arithProfile, bool shouldEmitProfiling)
86{
87 ASSERT(m_scratchGPR != m_src.payloadGPR());
88 ASSERT(m_scratchGPR != m_result.payloadGPR());
89 ASSERT(m_scratchGPR != InvalidGPRReg);
90#if USE(JSVALUE32_64)
91 ASSERT(m_scratchGPR != m_src.tagGPR());
92 ASSERT(m_scratchGPR != m_result.tagGPR());
93#endif
94
95 jit.moveValueRegs(m_src, m_result);
96 CCallHelpers::Jump srcNotInt = jit.branchIfNotInt32(m_src);
97
98 // -0 should produce a double, and hence cannot be negated as an int.
99 // The negative int32 0x80000000 doesn't have a positive int32 representation, and hence cannot be negated as an int.
100 slowPathJumpList.append(jit.branchTest32(CCallHelpers::Zero, m_src.payloadGPR(), CCallHelpers::TrustedImm32(0x7fffffff)));
101
102 jit.neg32(m_result.payloadGPR());
103#if USE(JSVALUE64)
104 jit.boxInt32(m_result.payloadGPR(), m_result);
105#endif
106 endJumpList.append(jit.jump());
107
108 srcNotInt.link(&jit);
109 slowPathJumpList.append(jit.branchIfNotNumber(m_src, m_scratchGPR));
110
111 // For a double, all we need to do is to invert the sign bit.
112#if USE(JSVALUE64)
113 jit.move(CCallHelpers::TrustedImm64((int64_t)(1ull << 63)), m_scratchGPR);
114 jit.xor64(m_scratchGPR, m_result.payloadGPR());
115#else
116 jit.xor32(CCallHelpers::TrustedImm32(1 << 31), m_result.tagGPR());
117#endif
118 // The flags of ArithNegate are basic in DFG.
119 // We only need to know if we ever produced a number.
120 if (shouldEmitProfiling && arithProfile && !arithProfile->argObservedType().sawNumber() && !arithProfile->didObserveDouble())
121 arithProfile->emitSetDouble(jit);
122 return true;
123}
124
125} // namespace JSC
126
127#endif // ENABLE(JIT)
Note: See TracBrowser for help on using the repository browser.