Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (155242 => 155243)
--- trunk/Source/_javascript_Core/ChangeLog 2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-09-07 05:47:57 UTC (rev 155243)
@@ -1,5 +1,56 @@
2013-09-06 Filip Pizlo <[email protected]>
+ FTL should support Call/Construct in the worst way possible
+ https://bugs.webkit.org/show_bug.cgi?id=120916
+
+ Reviewed by Oliver Hunt.
+
+ This adds support for Call/Construct by just calling out to C code that uses
+ the JSC::call/JSC::construct runtime functions for making calls. This is slow
+ and terrible, but it dramatically extends FTL coverage.
+
+ Supporting calls in a meaningful way meant also supporting
+ GlobalVarWatchpoint.
+
+ The extension of coverage helped to find a bunch of bugs:
+
+ - ObjectOrOtherUse was claimed to be supported in the FTL but speculate()
+ didn't support it. That means that any node with an ObjectOrOtherUse edge
+ that got DCE'd would cause the FTL to ICE.
+
+ - There was a bad fall-through compileCompareStrictEq() that led to ICE.
+
+ - The OSR exit reconstruction code was assuming it could do fast checks on
+ node->child1() before even determining the type of node; that crashes if
+ the node is HasVarArgs. Fixed by checking HasVarArgs first.
+
+ - The OSR exit compiler was using the wrong peekOffset for CArgumentGetter.
+ The default is 1, which assumes that you didn't push anything onto the
+ stack after getting called. The OSR exit thunks push FP, so the offset
+ should be 2.
+
+ This passes stress tests and is probably huge performance regression if you
+ --useExperimentalFTL=true. The regression will be fixed in
+ https://bugs.webkit.org/show_bug.cgi?id=113621.
+
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLIntrinsicRepository.h:
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileNode):
+ (JSC::FTL::LowerDFGToLLVM::compileGlobalVarWatchpoint):
+ (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
+ (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct):
+ (JSC::FTL::LowerDFGToLLVM::speculate):
+ (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther):
+ (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
+ * ftl/FTLOSRExitCompiler.cpp:
+ (JSC::FTL::compileStub):
+
+2013-09-06 Filip Pizlo <[email protected]>
+
jsc shell should destroy VM as a workaround for LLVM's exit-time destructors
https://bugs.webkit.org/show_bug.cgi?id=120921
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (155242 => 155243)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2013-09-07 05:47:57 UTC (rev 155243)
@@ -2200,6 +2200,46 @@
jitCode->optimizeAfterWarmUp(codeBlock);
return static_cast<char*>(address);
}
+
+// FIXME: Make calls work well. Currently they're a pure regression.
+// https://bugs.webkit.org/show_bug.cgi?id=113621
+EncodedJSValue DFG_OPERATION operationFTLCall(ExecState* exec)
+{
+ ExecState* callerExec = exec->callerFrame();
+
+ VM* vm = &callerExec->vm();
+ NativeCallFrameTracer tracer(vm, callerExec);
+
+ JSValue callee = exec->calleeAsValue();
+ CallData callData;
+ CallType callType = getCallData(callee, callData);
+ if (callType == CallTypeNone) {
+ vm->throwException(callerExec, createNotAFunctionError(callerExec, callee));
+ return JSValue::encode(jsUndefined());
+ }
+
+ return JSValue::encode(call(callerExec, callee, callType, callData, exec->thisValue(), exec));
+}
+
+// FIXME: Make calls work well. Currently they're a pure regression.
+// https://bugs.webkit.org/show_bug.cgi?id=113621
+EncodedJSValue DFG_OPERATION operationFTLConstruct(ExecState* exec)
+{
+ ExecState* callerExec = exec->callerFrame();
+
+ VM* vm = &callerExec->vm();
+ NativeCallFrameTracer tracer(vm, callerExec);
+
+ JSValue callee = exec->calleeAsValue();
+ ConstructData constructData;
+ ConstructType constructType = getConstructData(callee, constructData);
+ if (constructType == ConstructTypeNone) {
+ vm->throwException(callerExec, createNotAFunctionError(callerExec, callee));
+ return JSValue::encode(jsUndefined());
+ }
+
+ return JSValue::encode(construct(callerExec, callee, constructType, constructData, exec));
+}
#endif // ENABLE(FTL_JIT)
} // extern "C"
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (155242 => 155243)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2013-09-07 05:47:57 UTC (rev 155243)
@@ -254,6 +254,13 @@
char* DFG_OPERATION operationFindSwitchImmTargetForDouble(ExecState*, EncodedJSValue, size_t tableIndex);
char* DFG_OPERATION operationSwitchString(ExecState*, size_t tableIndex, JSString*);
+#if ENABLE(FTL_JIT)
+// FIXME: Make calls work well. Currently they're a pure regression.
+// https://bugs.webkit.org/show_bug.cgi?id=113621
+EncodedJSValue DFG_OPERATION operationFTLCall(ExecState*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationFTLConstruct(ExecState*) WTF_INTERNAL;
+#endif // ENABLE(FTL_JIT)
+
// This method is used to lookup an exception hander, keyed by faultLocation, which is
// the return location from one of the calls out to one of the helper operations above.
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (155242 => 155243)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2013-09-07 05:47:57 UTC (rev 155243)
@@ -86,6 +86,9 @@
case Upsilon:
case ExtractOSREntryLocal:
case LoopHint:
+ case Call:
+ case Construct:
+ case GlobalVarWatchpoint:
// These are OK.
break;
case GetArrayLength:
Modified: trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h (155242 => 155243)
--- trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h 2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h 2013-09-07 05:47:57 UTC (rev 155243)
@@ -46,6 +46,7 @@
#define FOR_EACH_FUNCTION_TYPE(macro) \
macro(I_DFGOperation_EJss, functionType(intPtr, intPtr, intPtr)) \
+ macro(J_DFGOperation_E, functionType(int64, intPtr)) \
macro(P_DFGOperation_EC, functionType(intPtr, intPtr, intPtr)) \
macro(V_DFGOperation_EOZD, functionType(voidType, intPtr, intPtr, int32, doubleType)) \
macro(V_DFGOperation_EOZJ, functionType(voidType, intPtr, intPtr, int32, int64))
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (155242 => 155243)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2013-09-07 05:47:57 UTC (rev 155243)
@@ -363,6 +363,9 @@
case PutGlobalVar:
compilePutGlobalVar();
break;
+ case GlobalVarWatchpoint:
+ compileGlobalVarWatchpoint();
+ break;
case CompareEq:
compileCompareEq();
break;
@@ -390,6 +393,10 @@
case LogicalNot:
compileLogicalNot();
break;
+ case Call:
+ case Construct:
+ compileCallOrConstruct();
+ break;
case Jump:
compileJump();
break;
@@ -1396,6 +1403,12 @@
lowJSValue(m_node->child1()), m_out.absolute(m_node->registerPointer()));
}
+ void compileGlobalVarWatchpoint()
+ {
+ // FIXME: Implement watchpoints.
+ // https://bugs.webkit.org/show_bug.cgi?id=113647
+ }
+
void compileCompareEq()
{
if (m_node->isBinaryUseKind(Int32Use)
@@ -1428,6 +1441,7 @@
if (m_node->isBinaryUseKind(NumberUse)) {
setBoolean(
m_out.doubleEqual(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
+ return;
}
if (m_node->isBinaryUseKind(ObjectUse)) {
@@ -1541,6 +1555,39 @@
setBoolean(m_out.bitNot(boolify(m_node->child1())));
}
+ void compileCallOrConstruct()
+ {
+ // FIXME: This is unacceptably slow.
+ // https://bugs.webkit.org/show_bug.cgi?id=113621
+
+ J_DFGOperation_E function =
+ m_node->op() == Call ? operationFTLCall : operationFTLConstruct;
+
+ int dummyThisArgument = m_node->op() == Call ? 0 : 1;
+
+ int numPassedArgs = m_node->numChildren() - 1;
+
+ LValue calleeFrame = m_out.add(
+ m_callFrame,
+ m_out.constIntPtr(sizeof(Register) * codeBlock()->m_numCalleeRegisters));
+
+ m_out.store32(
+ m_out.constInt32(numPassedArgs + dummyThisArgument),
+ payloadFor(calleeFrame, JSStack::ArgumentCount));
+ m_out.store64(m_callFrame, addressFor(calleeFrame, JSStack::CallerFrame));
+ m_out.store64(
+ lowJSValue(m_graph.varArgChild(m_node, 0)),
+ addressFor(calleeFrame, JSStack::Callee));
+
+ for (int i = 0; i < numPassedArgs; ++i) {
+ m_out.store64(
+ lowJSValue(m_graph.varArgChild(m_node, 1 + i)),
+ addressFor(calleeFrame, argumentToOperand(i + dummyThisArgument)));
+ }
+
+ setJSValue(vmCall(m_out.operation(function), calleeFrame));
+ }
+
void compileJump()
{
m_out.jump(lowBlock(m_node->takenBlock()));
@@ -2212,6 +2259,9 @@
case ObjectUse:
speculateObject(edge);
break;
+ case ObjectOrOtherUse:
+ speculateObjectOrOther(edge);
+ break;
case StringUse:
speculateString(edge);
break;
@@ -2225,6 +2275,7 @@
speculateBoolean(edge);
break;
default:
+ dataLog("Unsupported speculation use kind: ", edge.useKind(), "\n");
RELEASE_ASSERT_NOT_REACHED();
}
}
@@ -2278,6 +2329,42 @@
speculateObject(edge, lowCell(edge));
}
+ void speculateObjectOrOther(Edge edge)
+ {
+ if (!m_interpreter.needsTypeCheck(edge))
+ return;
+
+ LValue value = lowJSValue(edge);
+
+ LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther cell case"));
+ LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther primitive case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther continuation"));
+
+ m_out.branch(isNotCell(value), primitiveCase, cellCase);
+
+ LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
+
+ FTL_TYPE_CHECK(
+ jsValueValue(value), edge, (~SpecCell) | SpecObject,
+ m_out.equal(
+ m_out.loadPtr(value, m_heaps.JSCell_structure),
+ m_out.constIntPtr(vm().stringStructure.get())));
+
+ m_out.jump(continuation);
+
+ m_out.appendTo(primitiveCase, continuation);
+
+ FTL_TYPE_CHECK(
+ jsValueValue(value), edge, SpecCell | SpecOther,
+ m_out.notEqual(
+ m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
+ m_out.constInt64(ValueNull)));
+
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ }
+
void speculateString(Edge edge, LValue cell)
{
FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecString, isNotString(cell));
@@ -2634,6 +2721,8 @@
HashSet<Node*>::iterator end = m_live.end();
for (; iter != end; ++iter) {
Node* candidate = *iter;
+ if (candidate->flags() & NodeHasVarArgs)
+ continue;
if (!candidate->child1())
continue;
if (candidate->child1() != node)
Modified: trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp (155242 => 155243)
--- trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp 2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp 2013-09-07 05:47:57 UTC (rev 155243)
@@ -56,7 +56,7 @@
// of: we know that it's two frames beneath us. This is terrible and I feel
// ashamed of it, but it will work for now.
- CArgumentGetter arguments(jit);
+ CArgumentGetter arguments(jit, 2);
// First recover our call frame and tag thingies.
arguments.loadNextPtr(GPRInfo::callFrameRegister);