Modified: trunk/Source/_javascript_Core/ChangeLog (203785 => 203786)
--- trunk/Source/_javascript_Core/ChangeLog 2016-07-27 18:46:42 UTC (rev 203785)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-07-27 19:56:28 UTC (rev 203786)
@@ -1,3 +1,55 @@
+2016-07-27 Saam Barati <sbar...@apple.com>
+
+ MathICs should be able to emit only a jump along the inline path when they don't have any type data
+ https://bugs.webkit.org/show_bug.cgi?id=160110
+
+ Reviewed by Mark Lam.
+
+ This patch allows for MathIC fast-path generation to be delayed.
+ We delay when we don't see any observed type information for
+ the lhs/rhs operand, which implies that the MathIC has never
+ executed. This is profitable for two main reasons:
+ 1. If the math operation never executes, we emit much less code.
+ 2. Once we get type information for the lhs/rhs, we can emit better code.
+
+ To implement this, we just emit a jump to the slow path call
+ that will repatch on first execution.
+
+ New data for add:
+ | JetStream | Unity 3D |
+ ------| -------------|--------------
+ Old | 148 bytes | 143 bytes |
+ ------| -------------|--------------
+ New | 116 bytes | 113 bytes |
+ ------------------------------------
+
+ New data for mul:
+ | JetStream | Unity 3D |
+ ------| -------------|--------------
+ Old | 210 bytes | 185 bytes |
+ ------| -------------|--------------
+ New | 170 bytes | 137 bytes |
+ ------------------------------------
+
+ * jit/JITAddGenerator.cpp:
+ (JSC::JITAddGenerator::generateInline):
+ * jit/JITAddGenerator.h:
+ (JSC::JITAddGenerator::isLeftOperandValidConstant):
+ (JSC::JITAddGenerator::isRightOperandValidConstant):
+ (JSC::JITAddGenerator::arithProfile):
+ * jit/JITMathIC.h:
+ (JSC::JITMathIC::generateInline):
+ (JSC::JITMathIC::generateOutOfLine):
+ (JSC::JITMathIC::finalizeInlineCode):
+ * jit/JITMathICInlineResult.h:
+ * jit/JITMulGenerator.cpp:
+ (JSC::JITMulGenerator::generateInline):
+ * jit/JITMulGenerator.h:
+ (JSC::JITMulGenerator::isLeftOperandValidConstant):
+ (JSC::JITMulGenerator::isRightOperandValidConstant):
+ (JSC::JITMulGenerator::arithProfile):
+ * jit/JITOperations.cpp:
+
2016-07-26 Saam Barati <sbar...@apple.com>
rollout r203666
Modified: trunk/Source/_javascript_Core/jit/JITMathIC.h (203785 => 203786)
--- trunk/Source/_javascript_Core/jit/JITMathIC.h 2016-07-27 18:46:42 UTC (rev 203785)
+++ trunk/Source/_javascript_Core/jit/JITMathIC.h 2016-07-27 19:56:28 UTC (rev 203786)
@@ -27,6 +27,7 @@
#if ENABLE(JIT)
+#include "ArithProfile.h"
#include "CCallHelpers.h"
#include "JITAddGenerator.h"
#include "JITMathICInlineResult.h"
@@ -64,6 +65,24 @@
{
state.fastPathStart = jit.label();
size_t startSize = jit.m_assembler.buffer().codeSize();
+
+ if (ArithProfile* arithProfile = m_generator.arithProfile()) {
+ if (arithProfile->lhsObservedType().isEmpty() || arithProfile->rhsObservedType().isEmpty()) {
+ // It looks like the MathIC has yet to execute. We don't want to emit code in this
+ // case for a couple reasons. First, the operation may never execute, so if we don't emit
+ // code, it's a win. Second, if the operation does execute, we can emit better code
+ // once we have an idea about the types of lhs and rhs.
+ state.slowPathJumps.append(jit.patchableJump());
+ state.shouldSlowPathRepatch = true;
+ state.fastPathEnd = jit.label();
+ ASSERT(!m_generateFastPathOnRepatch); // We should have gathered some observed type info for lhs and rhs before trying to regenerate again.
+ m_generateFastPathOnRepatch = true;
+ size_t inlineSize = jit.m_assembler.buffer().codeSize() - startSize;
+ ASSERT_UNUSED(inlineSize, static_cast<ptrdiff_t>(inlineSize) <= MacroAssembler::maxJumpReplacementSize());
+ return true;
+ }
+ }
+
JITMathICInlineResult result = m_generator.generateInline(jit, state);
switch (result) {
@@ -100,10 +119,64 @@
void generateOutOfLine(VM& vm, CodeBlock* codeBlock, FunctionPtr callReplacement)
{
+ auto linkJumpToOutOfLineSnippet = [&] () {
+ CCallHelpers jit(&vm, codeBlock);
+ auto jump = jit.jump();
+ // We don't need a nop sled here because nobody should be jumping into the middle of an IC.
+ bool needsBranchCompaction = false;
+ RELEASE_ASSERT(jit.m_assembler.buffer().codeSize() <= static_cast<size_t>(m_inlineSize));
+ LinkBuffer linkBuffer(jit, m_inlineStart.dataLocation(), jit.m_assembler.buffer().codeSize(), JITCompilationMustSucceed, needsBranchCompaction);
+ RELEASE_ASSERT(linkBuffer.isValid());
+ linkBuffer.link(jump, CodeLocationLabel(m_code.code()));
+ FINALIZE_CODE(linkBuffer, ("JITMathIC: linking constant jump to out of line stub"));
+ };
+
+ auto replaceCall = [&] () {
+ ftlThunkAwareRepatchCall(codeBlock, slowPathCallLocation(), callReplacement);
+ };
+
+ bool shouldEmitProfiling = !JITCode::isOptimizingJIT(codeBlock->jitType());
+
+ if (m_generateFastPathOnRepatch) {
+
+ CCallHelpers jit(&vm, codeBlock);
+ MathICGenerationState generationState;
+ bool generatedInline = generateInline(jit, generationState, shouldEmitProfiling);
+
+ // We no longer want to try to regenerate the fast path.
+ m_generateFastPathOnRepatch = false;
+
+ if (generatedInline) {
+ auto jumpToDone = jit.jump();
+
+ LinkBuffer linkBuffer(vm, jit, codeBlock, JITCompilationCanFail);
+ if (!linkBuffer.didFailToAllocate()) {
+ linkBuffer.link(generationState.slowPathJumps, slowPathStartLocation());
+ linkBuffer.link(jumpToDone, doneLocation());
+
+ m_code = FINALIZE_CODE_FOR(
+ codeBlock, linkBuffer, ("JITMathIC: generating out of line fast IC snippet"));
+
+ if (!generationState.shouldSlowPathRepatch) {
+ // We won't need to regenerate, so we can wire the slow path call
+ // to a non repatching variant.
+ replaceCall();
+ }
+
+ linkJumpToOutOfLineSnippet();
+
+ return;
+ }
+ }
+
+ // We weren't able to generate an out of line fast path.
+ // We just generate the snippet in its full generality.
+ }
+
// We rewire to the alternate regardless of whether or not we can allocate the out of line path
// because if we fail allocating the out of line path, we don't want to waste time trying to
// allocate it in the future.
- ftlThunkAwareRepatchCall(codeBlock, slowPathCallLocation(), callReplacement);
+ replaceCall();
{
CCallHelpers jit(&vm, codeBlock);
@@ -111,7 +184,6 @@
MacroAssembler::JumpList endJumpList;
MacroAssembler::JumpList slowPathJumpList;
- bool shouldEmitProfiling = !JITCode::isOptimizingJIT(codeBlock->jitType());
bool emittedFastPath = m_generator.generateFastPath(jit, endJumpList, slowPathJumpList, shouldEmitProfiling);
if (!emittedFastPath)
return;
@@ -128,17 +200,7 @@
codeBlock, linkBuffer, ("JITMathIC: generating out of line IC snippet"));
}
- {
- CCallHelpers jit(&vm, codeBlock);
- auto jump = jit.jump();
- // We don't need a nop sled here because nobody should be jumping into the middle of an IC.
- bool needsBranchCompaction = false;
- RELEASE_ASSERT(jit.m_assembler.buffer().codeSize() <= static_cast<size_t>(m_inlineSize));
- LinkBuffer linkBuffer(jit, m_inlineStart.dataLocation(), jit.m_assembler.buffer().codeSize(), JITCompilationMustSucceed, needsBranchCompaction);
- RELEASE_ASSERT(linkBuffer.isValid());
- linkBuffer.link(jump, CodeLocationLabel(m_code.code()));
- FINALIZE_CODE(linkBuffer, ("JITMathIC: linking constant jump to out of line stub"));
- }
+ linkJumpToOutOfLineSnippet();
}
void finalizeInlineCode(const MathICGenerationState& state, LinkBuffer& linkBuffer)
@@ -172,6 +234,7 @@
int32_t m_inlineSize;
int32_t m_deltaFromStartToSlowPathCallLocation;
int32_t m_deltaFromStartToSlowPathStart;
+ bool m_generateFastPathOnRepatch { false };
GeneratorType m_generator;
};
Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (203785 => 203786)
--- trunk/Source/_javascript_Core/jit/JITOperations.cpp 2016-07-27 18:46:42 UTC (rev 203785)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp 2016-07-27 19:56:28 UTC (rev 203786)
@@ -2319,7 +2319,12 @@
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
+ JSValue op1 = JSValue::decode(encodedOp1);
+ JSValue op2 = JSValue::decode(encodedOp2);
+
auto nonOptimizeVariant = operationValueAddNoOptimize;
+ if (ArithProfile* arithProfile = addIC->m_generator.arithProfile())
+ arithProfile->observeLHSAndRHS(op1, op2);
addIC->generateOutOfLine(*vm, exec->codeBlock(), nonOptimizeVariant);
#if ENABLE(MATH_IC_STATS)
@@ -2326,8 +2331,6 @@
exec->codeBlock()->dumpMathICStats();
#endif
- JSValue op1 = JSValue::decode(encodedOp1);
- JSValue op2 = JSValue::decode(encodedOp2);
return JSValue::encode(jsAdd(exec, op1, op2));
}
@@ -2392,6 +2395,8 @@
NativeCallFrameTracer tracer(vm, exec);
auto nonOptimizeVariant = operationValueMulNoOptimize;
+ if (ArithProfile* arithProfile = mulIC->m_generator.arithProfile())
+ arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
mulIC->generateOutOfLine(*vm, exec->codeBlock(), nonOptimizeVariant);
#if ENABLE(MATH_IC_STATS)