We should ensure that operationStrCat2 and operationStrCat3 are never passed Symbols as arguments.
https://bugs.webkit.org/show_bug.cgi?id=179562
<rdar://problem/35467022>
Reviewed by Saam Barati.
JSTests:
* regress-179562.js: Added.
Source/JavaScriptCore:
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGOperations.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculateNotSymbol):
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::speculate):
(JSC::FTL::DFG::LowerDFGToB3::speculateNotSymbol):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@224735 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 443c4d3..d2ed53a 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -200,6 +200,14 @@
node,
[&] (Edge& edge) {
fixEdge<KnownPrimitiveUse>(edge);
+ // StrCat automatically coerces the values into strings before concatenating them.
+ // The ECMA spec says that we're not allowed to automatically coerce a Symbol into
+ // a string. If a Symbol is encountered, a TypeError will be thrown. As a result,
+ // our runtime functions for this slow path expect that they will never be passed
+ // Symbols.
+ m_insertionSet.insertNode(
+ m_indexInBlock, SpecNone, Check, node->origin,
+ Edge(edge.node(), NotSymbolUse));
});
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 96fcaf6..a55711d 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1985,8 +1985,10 @@
NativeCallFrameTracer tracer(&vm, exec);
auto scope = DECLARE_THROW_SCOPE(vm);
+ ASSERT(!JSValue::decode(a).isSymbol());
+ ASSERT(!JSValue::decode(b).isSymbol());
JSString* str1 = JSValue::decode(a).toString(exec);
- scope.assertNoException(); // Impossible, since we must have been given primitives.
+ scope.assertNoException(); // Impossible, since we must have been given non-Symbol primitives.
JSString* str2 = JSValue::decode(b).toString(exec);
scope.assertNoException();
@@ -2000,8 +2002,11 @@
NativeCallFrameTracer tracer(&vm, exec);
auto scope = DECLARE_THROW_SCOPE(vm);
+ ASSERT(!JSValue::decode(a).isSymbol());
+ ASSERT(!JSValue::decode(b).isSymbol());
+ ASSERT(!JSValue::decode(c).isSymbol());
JSString* str1 = JSValue::decode(a).toString(exec);
- scope.assertNoException(); // Impossible, since we must have been given primitives.
+ scope.assertNoException(); // Impossible, since we must have been given non-Symbol primitives.
JSString* str2 = JSValue::decode(b).toString(exec);
scope.assertNoException();
JSString* str3 = JSValue::decode(c).toString(exec);
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 4f5bbb8..19d2e0b 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -73,6 +73,7 @@
case StringObjectUse:
case StringOrStringObjectUse:
case NotStringVarUse:
+ case NotSymbolUse:
case NotCellUse:
case OtherUse:
case MiscUse:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 5778f33..b8c6d79 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -9542,6 +9542,28 @@
notCell.link(&m_jit);
}
+void SpeculativeJIT::speculateNotSymbol(Edge edge)
+{
+ if (!needsTypeCheck(edge, ~SpecSymbol))
+ return;
+
+ JSValueOperand operand(this, edge, ManualOperandSpeculation);
+ auto valueRegs = operand.jsValueRegs();
+ GPRReg value = valueRegs.payloadGPR();
+ JITCompiler::Jump notCell;
+
+ bool needsCellCheck = needsTypeCheck(edge, SpecCell);
+ if (needsCellCheck)
+ notCell = m_jit.branchIfNotCell(valueRegs);
+
+ speculationCheck(BadType, JSValueSource::unboxedCell(value), edge.node(), m_jit.branchIfSymbol(value));
+
+ if (needsCellCheck)
+ notCell.link(&m_jit);
+
+ m_interpreter.filter(edge, ~SpecSymbol);
+}
+
void SpeculativeJIT::speculateSymbol(Edge edge, GPRReg cell)
{
DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, ~SpecCellCheck | SpecSymbol, m_jit.branchIfNotSymbol(cell));
@@ -9731,6 +9753,9 @@
case NotStringVarUse:
speculateNotStringVar(edge);
break;
+ case NotSymbolUse:
+ speculateNotSymbol(edge);
+ break;
case NotCellUse:
speculateNotCell(edge);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 2f2b0dd..99ebf18 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -3158,6 +3158,7 @@
void speculateStringOrOther(Edge, JSValueRegs, GPRReg scratch);
void speculateStringOrOther(Edge);
void speculateNotStringVar(Edge);
+ void speculateNotSymbol(Edge);
template<typename StructureLocationType>
void speculateStringObjectForStructure(Edge, StructureLocationType);
void speculateStringObject(Edge, GPRReg);
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.cpp b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
index 23d0db0..bd9419f 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.cpp
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
@@ -145,6 +145,9 @@
case NotStringVarUse:
out.print("NotStringVar");
return;
+ case NotSymbolUse:
+ out.print("NotSymbol");
+ return;
case NotCellUse:
out.print("NotCell");
return;
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.h b/Source/JavaScriptCore/dfg/DFGUseKind.h
index 796d8b40..c6b549f 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.h
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.h
@@ -72,6 +72,7 @@
StringObjectUse,
StringOrStringObjectUse,
NotStringVarUse,
+ NotSymbolUse,
NotCellUse,
OtherUse,
MiscUse,
@@ -161,6 +162,8 @@
return SpecString | SpecStringObject;
case NotStringVarUse:
return ~SpecStringVar;
+ case NotSymbolUse:
+ return ~SpecSymbol;
case NotCellUse:
return ~SpecCellCheck;
case OtherUse: