Diff
Modified: branches/jsCStack/Source/_javascript_Core/ChangeLog (161731 => 161732)
--- branches/jsCStack/Source/_javascript_Core/ChangeLog 2014-01-11 05:02:01 UTC (rev 161731)
+++ branches/jsCStack/Source/_javascript_Core/ChangeLog 2014-01-11 05:06:10 UTC (rev 161732)
@@ -1,5 +1,35 @@
2014-01-10 Filip Pizlo <[email protected]>
+ FTL should enough things to compile inlined closure calls (like CheckExecutable and GetScope)
+ https://bugs.webkit.org/show_bug.cgi?id=126799
+
+ Reviewed by Oliver Hunt.
+
+ Added FTL support for CheckExecutable and GetScope because I wanted to compile
+ closure calls. But then I realized that closure call inlining was broken because
+ the baseline JIT would link the closure stubs to the slow path, thereby causing
+ the DFG's profiling to think that all closure calls are actually virtual calls.
+
+ Also fixed some hash() computing stuff to make debugging easier.
+
+ * ftl/FTLAbstractHeapRepository.h:
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileNode):
+ (JSC::FTL::LowerDFGToLLVM::compileCheckExecutable):
+ (JSC::FTL::LowerDFGToLLVM::compileGetScope):
+ * jit/Repatch.cpp:
+ (JSC::linkClosureCall):
+ * runtime/Options.cpp:
+ (JSC::recomputeDependentOptions):
+ (JSC::Options::initialize):
+ (JSC::Options::setOption):
+ * tests/stress/inline-closure-call.js: Added.
+ (bar):
+
+2014-01-10 Filip Pizlo <[email protected]>
+
It should be easier to diagnose FTL performance issues due to register preservation thunks
https://bugs.webkit.org/show_bug.cgi?id=126798
Modified: branches/jsCStack/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h (161731 => 161732)
--- branches/jsCStack/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h 2014-01-11 05:02:01 UTC (rev 161731)
+++ branches/jsCStack/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h 2014-01-11 05:06:10 UTC (rev 161732)
@@ -47,6 +47,8 @@
macro(JSArrayBufferView_mode, JSArrayBufferView::offsetOfMode()) \
macro(JSArrayBufferView_vector, JSArrayBufferView::offsetOfVector()) \
macro(JSCell_structure, JSCell::structureOffset()) \
+ macro(JSFunction_executable, JSFunction::offsetOfExecutable()) \
+ macro(JSFunction_scope, JSFunction::offsetOfScopeChain()) \
macro(JSObject_butterfly, JSObject::butterflyOffset()) \
macro(JSScope_next, JSScope::offsetOfNext()) \
macro(JSString_length, JSString::offsetOfLength()) \
Modified: branches/jsCStack/Source/_javascript_Core/ftl/FTLCapabilities.cpp (161731 => 161732)
--- branches/jsCStack/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2014-01-11 05:02:01 UTC (rev 161731)
+++ branches/jsCStack/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2014-01-11 05:06:10 UTC (rev 161732)
@@ -116,6 +116,8 @@
case CheckInBounds:
case ConstantStoragePointer:
case Check:
+ case CheckExecutable:
+ case GetScope:
// These are OK.
break;
case GetById:
Modified: branches/jsCStack/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (161731 => 161732)
--- branches/jsCStack/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2014-01-11 05:02:01 UTC (rev 161731)
+++ branches/jsCStack/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2014-01-11 05:06:10 UTC (rev 161732)
@@ -353,6 +353,9 @@
case CheckFunction:
compileCheckFunction();
break;
+ case CheckExecutable:
+ compileCheckExecutable();
+ break;
case ArrayifyToStructure:
compileArrayifyToStructure();
break;
@@ -427,6 +430,9 @@
case NotifyWrite:
compileNotifyWrite();
break;
+ case GetScope:
+ compileGetScope();
+ break;
case GetMyScope:
compileGetMyScope();
break;
@@ -1333,6 +1339,17 @@
m_out.notEqual(cell, weakPointer(m_node->function())));
}
+ void compileCheckExecutable()
+ {
+ LValue cell = lowCell(m_node->child1());
+
+ speculate(
+ BadExecutable, jsValueValue(cell), m_node->child1().node(),
+ m_out.notEqual(
+ m_out.loadPtr(cell, m_heaps.JSFunction_executable),
+ weakPointer(m_node->function())));
+ }
+
void compileArrayifyToStructure()
{
LValue cell = lowCell(m_node->child1());
@@ -2403,6 +2420,11 @@
m_out.appendTo(continuation, lastNext);
}
+ void compileGetScope()
+ {
+ setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSFunction_scope));
+ }
+
void compileGetMyScope()
{
setJSValue(m_out.loadPtr(addressFor(
Modified: branches/jsCStack/Source/_javascript_Core/jit/Repatch.cpp (161731 => 161732)
--- branches/jsCStack/Source/_javascript_Core/jit/Repatch.cpp 2014-01-11 05:02:01 UTC (rev 161731)
+++ branches/jsCStack/Source/_javascript_Core/jit/Repatch.cpp 2014-01-11 05:06:10 UTC (rev 161732)
@@ -1406,7 +1406,10 @@
LinkBuffer patchBuffer(*vm, &stubJit, callerCodeBlock);
patchBuffer.link(call, FunctionPtr(codePtr.executableAddress()));
- patchBuffer.link(done, callLinkInfo.callReturnLocation.labelAtOffset(0));
+ if (JITCode::isOptimizingJIT(callerCodeBlock->jitType()))
+ patchBuffer.link(done, callLinkInfo.callReturnLocation.labelAtOffset(0));
+ else
+ patchBuffer.link(done, callLinkInfo.hotPathOther.labelAtOffset(0));
patchBuffer.link(slow, CodeLocationLabel(vm->getCTIStub(virtualThunkGeneratorFor(CodeForCall, registers)).code()));
RefPtr<ClosureCallStubRoutine> stubRoutine = adoptRef(new ClosureCallStubRoutine(
Modified: branches/jsCStack/Source/_javascript_Core/runtime/Options.cpp (161731 => 161732)
--- branches/jsCStack/Source/_javascript_Core/runtime/Options.cpp 2014-01-11 05:02:01 UTC (rev 161731)
+++ branches/jsCStack/Source/_javascript_Core/runtime/Options.cpp 2014-01-11 05:06:10 UTC (rev 161732)
@@ -31,6 +31,7 @@
#include <limits>
#include <stdlib.h>
#include <string.h>
+#include <wtf/DataLog.h>
#include <wtf/NumberOfCores.h>
#include <wtf/PageBlock.h>
#include <wtf/StdLibExtras.h>
@@ -175,6 +176,49 @@
#undef FOR_EACH_OPTION
};
+static void recomputeDependentOptions()
+{
+#if !ENABLE(JIT)
+ Options::useJIT() = false;
+ Options::useDFGJIT() = false;
+#endif
+#if !ENABLE(YARR_JIT)
+ Options::useRegExpJIT() = false;
+#endif
+
+ if (Options::showDisassembly()
+ || Options::showDFGDisassembly()
+ || Options::dumpBytecodeAtDFGTime()
+ || Options::dumpGraphAtEachPhase()
+ || Options::verboseCompilation()
+ || Options::logCompilationChanges()
+ || Options::validateGraph()
+ || Options::validateGraphAtEachPhase()
+ || Options::verboseOSR()
+ || Options::verboseCompilationQueue()
+ || Options::reportCompileTimes()
+ || Options::verboseCFA()
+ || Options::verboseFTLFailure())
+ Options::alwaysComputeHash() = true;
+
+ // Do range checks where needed and make corrections to the options:
+ ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp());
+ ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon());
+ ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0);
+
+ // Compute the maximum value of the reoptimization retry counter. This is simply
+ // the largest value at which we don't overflow the execute counter, when using it
+ // to left-shift the execution counter by this amount. Currently the value ends
+ // up being 18, so this loop is not so terrible; it probably takes up ~100 cycles
+ // total on a 32-bit processor.
+ Options::reoptimizationRetryCounterMax() = 0;
+ while ((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << (Options::reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()))
+ Options::reoptimizationRetryCounterMax()++;
+
+ ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) > 0);
+ ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
+}
+
void Options::initialize()
{
// Initialize each of the options with their default values:
@@ -204,45 +248,7 @@
; // Deconfuse editors that do auto indentation
#endif
-#if !ENABLE(JIT)
- useJIT() = false;
- useDFGJIT() = false;
-#endif
-#if !ENABLE(YARR_JIT)
- useRegExpJIT() = false;
-#endif
-
- if (showDisassembly()
- || showDFGDisassembly()
- || dumpBytecodeAtDFGTime()
- || dumpGraphAtEachPhase()
- || verboseCompilation()
- || logCompilationChanges()
- || validateGraph()
- || validateGraphAtEachPhase()
- || verboseOSR()
- || verboseCompilationQueue()
- || reportCompileTimes()
- || verboseCFA()
- || verboseFTLFailure())
- alwaysComputeHash() = true;
-
- // Do range checks where needed and make corrections to the options:
- ASSERT(thresholdForOptimizeAfterLongWarmUp() >= thresholdForOptimizeAfterWarmUp());
- ASSERT(thresholdForOptimizeAfterWarmUp() >= thresholdForOptimizeSoon());
- ASSERT(thresholdForOptimizeAfterWarmUp() >= 0);
-
- // Compute the maximum value of the reoptimization retry counter. This is simply
- // the largest value at which we don't overflow the execute counter, when using it
- // to left-shift the execution counter by this amount. Currently the value ends
- // up being 18, so this loop is not so terrible; it probably takes up ~100 cycles
- // total on a 32-bit processor.
- reoptimizationRetryCounterMax() = 0;
- while ((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << (reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32>::max()))
- reoptimizationRetryCounterMax()++;
-
- ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) > 0);
- ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32>::max()));
+ recomputeDependentOptions();
}
// Parses a single command line option in the format "<optionName>=<value>"
@@ -266,6 +272,7 @@
bool success = parse(valueStr, value); \
if (success) { \
name_() = value; \
+ recomputeDependentOptions(); \
return true; \
} \
return false; \
@@ -274,7 +281,7 @@
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
- return false; // No option matched.
+ return false; // No option matched.
}
void Options::dumpAllOptions(FILE* stream)
Added: branches/jsCStack/Source/_javascript_Core/tests/stress/inline-closure-call.js (0 => 161732)
--- branches/jsCStack/Source/_javascript_Core/tests/stress/inline-closure-call.js (rev 0)
+++ branches/jsCStack/Source/_javascript_Core/tests/stress/inline-closure-call.js 2014-01-11 05:06:10 UTC (rev 161732)
@@ -0,0 +1,16 @@
+function foo(x) {
+ return function(y) { return x + y; }
+}
+
+function bar(a, b) {
+ return foo(a)(b);
+}
+
+noInline(foo);
+noInline(bar);
+
+for (var i = 0; i < 100000; ++i) {
+ var result = bar(i, i + 1);
+ if (result != i * 2 + 1)
+ throw "Error: bad result for " + i + ": " + result;
+}