[JSC] add DFG/FTL support for op_to_property_key
https://bugs.webkit.org/show_bug.cgi?id=206368
JSTests:
Reviewed by Saam Barati.
* stress/class-fields-to-property-key-const-string-ftl.js: Added.
* stress/class-fields-to-property-key-const-symbol-ftl.js: Added.
* stress/class-fields-to-property-key-slow-object-tostring-ftl.js: Added.
* stress/class-fields-to-property-key-slow-object-valueof-ftl.js: Added.
* stress/class-fields-to-property-key-string-object-ftl.js: Added.
* stress/class-fields-to-property-key-string-or-string-object-ftl.js: Added.
Source/JavaScriptCore:
Reviewed by Saam Barati.
Implement DFG/FTL support for the op_to_property_key opcode. This operates
similar to the LLInt and base JIT implementations, in which we avoid invoking
the full ToPropertyKey operation if the source operand is already a String or
Symbol at runtime.
If DFG/FTL are confident the value will be a String or Symbol at compile time,
the operation is omitted entirely in the final graph.
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToToString):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileToPrimitive):
(JSC::DFG::SpeculativeJIT::compileToPropertyKey):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileToPropertyKey):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@254801 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index d0f6afc..6109d9f 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,17 @@
+2020-01-18 Caitlin Potter <caitp@igalia.com>
+
+ [JSC] add DFG/FTL support for op_to_property_key
+ https://bugs.webkit.org/show_bug.cgi?id=206368
+
+ Reviewed by Saam Barati.
+
+ * stress/class-fields-to-property-key-const-string-ftl.js: Added.
+ * stress/class-fields-to-property-key-const-symbol-ftl.js: Added.
+ * stress/class-fields-to-property-key-slow-object-tostring-ftl.js: Added.
+ * stress/class-fields-to-property-key-slow-object-valueof-ftl.js: Added.
+ * stress/class-fields-to-property-key-string-object-ftl.js: Added.
+ * stress/class-fields-to-property-key-string-or-string-object-ftl.js: Added.
+
2020-01-17 Saam Barati <sbarati@apple.com>
Air O0 should have better stack allocation
diff --git a/JSTests/stress/class-fields-to-property-key-const-string-ftl.js b/JSTests/stress/class-fields-to-property-key-const-string-ftl.js
new file mode 100644
index 0000000..e64aff1
--- /dev/null
+++ b/JSTests/stress/class-fields-to-property-key-const-string-ftl.js
@@ -0,0 +1,25 @@
+//@ requireOptions("--useClassFields=true")
+//@ if isFTLEnabled then runFTLNoCJIT else skip end
+
+let ftlTrue = $vm.ftlTrue;
+let didFTLCompile = false;
+function constFoldString(i) {
+ class C {
+ ["foo"] = i;
+ }
+ didFTLCompile = ftlTrue();
+ let c = new C();
+ if (c.foo !== i)
+ throw new Error(`Failed on iteration ${i}\n${JSON.stringify(c)}`);
+}
+noInline(constFoldString);
+
+let i = 0;
+let maxTries = 10000;
+for (; i < maxTries && !numberOfDFGCompiles(constFoldString) && !didFTLCompile; ++i) {
+ optimizeNextInvocation(constFoldString);
+ constFoldString(i);
+}
+
+if (i >= maxTries)
+ throw new Error("Failed to compile constFoldString with DFG JIT");
diff --git a/JSTests/stress/class-fields-to-property-key-const-symbol-ftl.js b/JSTests/stress/class-fields-to-property-key-const-symbol-ftl.js
new file mode 100644
index 0000000..8e1b2e4
--- /dev/null
+++ b/JSTests/stress/class-fields-to-property-key-const-symbol-ftl.js
@@ -0,0 +1,26 @@
+//@ requireOptions("--useClassFields=true")
+//@ if isFTLEnabled then runFTLNoCJIT else skip end
+
+let ftlTrue = $vm.ftlTrue;
+let didFTLCompile = false;
+let symbol = Symbol("test");
+function constFoldSymbol(i) {
+ class C {
+ [symbol] = i;
+ }
+ didFTLCompile = ftlTrue();
+ let c = new C();
+ if (c[symbol] !== i)
+ throw new Error(`Failed on iteration ${i}\n${JSON.stringify(c)}`);
+}
+noInline(constFoldSymbol);
+
+let i = 0;
+let maxTries = 10000;
+for (; i < maxTries && !numberOfDFGCompiles(constFoldSymbol) && !didFTLCompile; ++i) {
+ optimizeNextInvocation(constFoldSymbol);
+ constFoldSymbol(i);
+}
+
+if (i >= maxTries)
+ throw new Error("Failed to compile with DFG JIT");
diff --git a/JSTests/stress/class-fields-to-property-key-slow-object-tostring-ftl.js b/JSTests/stress/class-fields-to-property-key-slow-object-tostring-ftl.js
new file mode 100644
index 0000000..d9b7cc4
--- /dev/null
+++ b/JSTests/stress/class-fields-to-property-key-slow-object-tostring-ftl.js
@@ -0,0 +1,33 @@
+//@ requireOptions("--useClassFields=true")
+//@ if isFTLEnabled then runFTLNoCJIT else skip end
+
+let ftlTrue = $vm.ftlTrue;
+let didFTLCompile = false;
+function slowObjectValueOf(i) {
+ let getToStringCalled = false;
+ let valueOfCalled = false;
+ let slowObject = {
+ get toString() { getToStringCalled = true; },
+ valueOf() { valueOfCalled = true; return "test"; }
+ };
+
+ class C {
+ [slowObject] = i;
+ }
+ didFTLCompile = ftlTrue();
+ if (!getToStringCalled || !valueOfCalled)
+ throw new Error(`Failed on iteration ${i} (getToStringCalled === ${getToStringCalled}, valueOfCalled == ${valueOfCalled})`);
+ let c = new C();
+ if (c.test !== i)
+ throw new Error(`Failed on iteration ${i}\n${JSON.stringify(c)}`);
+}
+
+let i = 0;
+let maxTries = 10000;
+for (i = 0; i < maxTries && !numberOfDFGCompiles(slowObjectValueOf) && !didFTLCompile; ++i) {
+ optimizeNextInvocation(slowObjectValueOf);
+ slowObjectValueOf(i);
+}
+
+if (i >= maxTries)
+ throw new Error("Failed to compile slowObjectValueOf with DFG JIT");
diff --git a/JSTests/stress/class-fields-to-property-key-slow-object-valueof-ftl.js b/JSTests/stress/class-fields-to-property-key-slow-object-valueof-ftl.js
new file mode 100644
index 0000000..2168b52
--- /dev/null
+++ b/JSTests/stress/class-fields-to-property-key-slow-object-valueof-ftl.js
@@ -0,0 +1,33 @@
+//@ requireOptions("--useClassFields=true")
+//@ if isFTLEnabled then runFTLNoCJIT else skip end
+
+let ftlTrue = $vm.ftlTrue;
+let didFTLCompile = false;
+function slowObjectValueOf(i) {
+ let getToStringCalled = false;
+ let valueOfCalled = false;
+ let slowObject = {
+ get toString() { getToStringCalled = true; },
+ valueOf() { valueOfCalled = true; return "test"; }
+ };
+
+ class C {
+ [slowObject] = i;
+ }
+ didFTLCompile = ftlTrue();
+ if (!getToStringCalled || !valueOfCalled)
+ throw new Error(`Failed on iteration ${i} (getToStringCalled === ${getToStringCalled}, valueOfCalled == ${valueOfCalled})`);
+ let c = new C();
+ if (c.test !== i)
+ throw new Error(`Failed on iteration ${i}\n${JSON.stringify(c)}`);
+}
+
+let i = 0;
+let maxTries = 10000;
+for (i = 0; i < !maxTries && !numberOfDFGCompiles(slowObjectValueOf) && !didFTLCompile; ++i) {
+ optimizeNextInvocation(slowObjectValueOf);
+ slowObjectValueOf(i);
+}
+
+if (i >= maxTries)
+ throw new Error("Failed to compile slowObjectValueOf with DFG JIT");
diff --git a/JSTests/stress/class-fields-to-property-key-string-object-ftl.js b/JSTests/stress/class-fields-to-property-key-string-object-ftl.js
new file mode 100644
index 0000000..86a089c
--- /dev/null
+++ b/JSTests/stress/class-fields-to-property-key-string-object-ftl.js
@@ -0,0 +1,25 @@
+//@ requireOptions("--useClassFields=true")
+//@ if isFTLEnabled then runFTLNoCJIT else skip end
+
+let ftlTrue = $vm.ftlTrue;
+let didFTLCompile = false;
+function stringObjectToString(i) {
+ class C {
+ [new String("foo")] = i;
+ }
+ didFTLCompile = ftlTrue();
+ let c = new C();
+ if (c.foo !== i)
+ throw new Error(`Failed on iteration ${i}\n${JSON.stringify(c)}`);
+}
+noInline(stringObjectToString);
+
+let i = 0;
+let maxTries = 30000;
+for (; i < maxTries && !numberOfDFGCompiles(stringObjectToString) && !didFTLCompile; ++i) {
+ optimizeNextInvocation(stringObjectToString);
+ stringObjectToString(i);
+}
+
+if (i >= maxTries)
+ throw new Error("Failed to compile stringObjectToString with DFG JIT");
diff --git a/JSTests/stress/class-fields-to-property-key-string-or-string-object-ftl.js b/JSTests/stress/class-fields-to-property-key-string-or-string-object-ftl.js
new file mode 100644
index 0000000..c53f725
--- /dev/null
+++ b/JSTests/stress/class-fields-to-property-key-string-or-string-object-ftl.js
@@ -0,0 +1,28 @@
+//@ requireOptions("--useClassFields=true")
+//@ if isFTLEnabled then runFTLNoCJIT else skip end
+
+let ftlTrue = $vm.ftlTrue;
+let didFTLCompile = false;
+function key(i) {
+ return (i & 1) ? new String("foo") : "foo";
+}
+function stringOrStringObjectToString(i) {
+ class C {
+ [key(i)] = i;
+ }
+ didFTLCompile = ftlTrue();
+ let c = new C();
+ if (c.foo !== i)
+ throw new Error(`Failed on iteration ${i}\n${JSON.stringify(c)}`);
+}
+noInline(stringOrStringObjectToString);
+
+let i = 0;
+let maxTries = 30000;
+for (; i < maxTries && !numberOfDFGCompiles(stringOrStringObjectToString) && !didFTLCompile; ++i) {
+ optimizeNextInvocation(stringOrStringObjectToString);
+ stringOrStringObjectToString(i);
+}
+
+if (i >= maxTries)
+ throw new Error("Failed to compile stringOrStringObjectToString with DFG JIT");
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index a68f127..01ba9f8 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,54 @@
+2020-01-18 Caitlin Potter <caitp@igalia.com>
+
+ [JSC] add DFG/FTL support for op_to_property_key
+ https://bugs.webkit.org/show_bug.cgi?id=206368
+
+ Reviewed by Saam Barati.
+
+ Implement DFG/FTL support for the op_to_property_key opcode. This operates
+ similar to the LLInt and base JIT implementations, in which we avoid invoking
+ the full ToPropertyKey operation if the source operand is already a String or
+ Symbol at runtime.
+
+ If DFG/FTL are confident the value will be a String or Symbol at compile time,
+ the operation is omitted entirely in the final graph.
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::convertToToString):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileToPrimitive):
+ (JSC::DFG::SpeculativeJIT::compileToPropertyKey):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileToPropertyKey):
+
2020-01-17 Saam Barati <sbarati@apple.com>
Air O0 should have better stack allocation
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index e5284ad..7be7e2c 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -2531,6 +2531,20 @@
break;
}
+ case ToPropertyKey: {
+ if (!(forNode(node->child1()).m_type & ~(SpecString | SpecSymbol))) {
+ m_state.setShouldTryConstantFolding(true);
+ didFoldClobberWorld();
+ setForNode(node, forNode(node->child1()));
+ break;
+ }
+
+ clobberWorld();
+
+ setTypeForNode(node, SpecString | SpecSymbol);
+ break;
+ }
+
case ToNumber: {
JSValue childConst = forNode(node->child1()).value();
if (childConst && childConst.isNumber()) {
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index bc01cfb..d1fa0b3 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -5603,7 +5603,14 @@
set(bytecode.m_dst, addToGraph(ToPrimitive, value));
NEXT_OPCODE(op_to_primitive);
}
-
+
+ case op_to_property_key: {
+ auto bytecode = currentInstruction->as<OpToPropertyKey>();
+ Node* value = get(bytecode.m_src);
+ set(bytecode.m_dst, addToGraph(ToPropertyKey, value));
+ NEXT_OPCODE(op_to_property_key);
+ }
+
case op_strcat: {
auto bytecode = currentInstruction->as<OpStrcat>();
int startOperand = bytecode.m_src.offset();
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index ce5f6aa..759b778 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -282,6 +282,7 @@
case op_new_regexp:
case op_get_internal_field:
case op_put_internal_field:
+ case op_to_property_key:
case op_unreachable:
case op_super_sampler_begin:
case op_super_sampler_end:
@@ -293,7 +294,6 @@
case op_yield:
case op_create_generator_frame_environment:
- case op_to_property_key: // FIXME: op_to_property_key will need DFG/FTL support to ship class fields.
case llint_program_prologue:
case llint_eval_prologue:
case llint_module_program_prologue:
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index eee9bae..81b0014 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -649,6 +649,7 @@
case ConstructVarargs:
case ConstructForwardVarargs:
case ToPrimitive:
+ case ToPropertyKey:
case InByVal:
case InById:
case HasOwnProperty:
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index cebb3c8..d8af035 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -717,6 +717,15 @@
break;
}
+ case ToPropertyKey: {
+ if (m_state.forNode(node->child1()).m_type & ~(SpecString | SpecSymbol))
+ break;
+
+ node->convertToIdentity();
+ changed = true;
+ break;
+ }
+
case ToThis: {
ToThisResult result = isToThisAnIdentity(m_graph.m_vm, m_graph.isStrictModeFor(node->origin.semantic), m_state.forNode(node->child1()));
if (result == ToThisResult::Identity) {
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index 1f30dff..6ee725a 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -336,6 +336,7 @@
case ToNumeric:
case ToObject:
case ToPrimitive:
+ case ToPropertyKey:
case ToThis:
case TryGetById:
case CreateThis:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 922d35b..c79cd7c 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -1391,6 +1391,38 @@
break;
}
+ case ToPropertyKey: {
+ if (node->child1()->shouldSpeculateString()) {
+ fixEdge<StringUse>(node->child1());
+ node->convertToIdentity();
+
+ return;
+ }
+
+ if (node->child1()->shouldSpeculateSymbol()) {
+ fixEdge<SymbolUse>(node->child1());
+ node->convertToIdentity();
+ return;
+ }
+
+ if (node->child1()->shouldSpeculateStringObject()
+ && m_graph.canOptimizeStringObjectAccess(node->origin.semantic)) {
+ addCheckStructureForOriginalStringObjectUse(StringObjectUse, node->origin, node->child1().node());
+ fixEdge<StringObjectUse>(node->child1());
+ node->convertToToString();
+ return;
+ }
+
+ if (node->child1()->shouldSpeculateStringOrStringObject()
+ && m_graph.canOptimizeStringObjectAccess(node->origin.semantic)) {
+ addCheckStructureForOriginalStringObjectUse(StringOrStringObjectUse, node->origin, node->child1().node());
+ fixEdge<StringOrStringObjectUse>(node->child1());
+ node->convertToToString();
+ return;
+ }
+ break;
+ }
+
case ToNumber: {
fixupToNumber(node);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 517af10..344a2ab 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -711,7 +711,7 @@
void convertToToString()
{
- ASSERT(m_op == ToPrimitive || m_op == StringValueOf);
+ ASSERT(m_op == ToPrimitive || m_op == StringValueOf || m_op == ToPropertyKey);
m_op = ToString;
}
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 7c6d1b2..547fe4d 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -402,6 +402,7 @@
macro(TypeOf, NodeResultJS) \
macro(LogicalNot, NodeResultBoolean) \
macro(ToPrimitive, NodeResultJS | NodeMustGenerate) \
+ macro(ToPropertyKey, NodeResultJS | NodeMustGenerate) \
macro(ToString, NodeResultJS | NodeMustGenerate) \
macro(ToNumber, NodeResultJS | NodeMustGenerate) \
macro(ToNumeric, NodeResultJS | NodeMustGenerate) \
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index f7ac7ce..2fdb9c9 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1649,6 +1649,15 @@
return JSValue::encode(JSValue::decode(value).toPrimitive(globalObject));
}
+EncodedJSValue JIT_OPERATION operationToPropertyKey(JSGlobalObject* globalObject, EncodedJSValue value)
+{
+ VM& vm = globalObject->vm();
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+ return JSValue::encode(JSValue::decode(value).toPropertyKeyValue(globalObject));
+}
+
EncodedJSValue JIT_OPERATION operationToNumber(JSGlobalObject* globalObject, EncodedJSValue value)
{
VM& vm = globalObject->vm();
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index a33ede9..0f1c875 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -91,6 +91,7 @@
EncodedJSValue JIT_OPERATION operationGetByValObjectString(JSGlobalObject*, JSCell*, JSCell* string) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationGetByValObjectSymbol(JSGlobalObject*, JSCell*, JSCell* symbol) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationToPrimitive(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationToPropertyKey(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationToNumber(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationToNumeric(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationGetByValWithThis(JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index f92ae9d..9b8d60d 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -575,6 +575,13 @@
break;
}
+ case ToPropertyKey: {
+ SpeculatedType child = node->child1()->prediction();
+ if (child)
+ changed |= mergePrediction(resultOfToPropertyKey(child));
+ break;
+ }
+
case NormalizeMapKey: {
SpeculatedType prediction = node->child1()->prediction();
if (prediction)
@@ -1222,6 +1229,7 @@
case GetByVal:
case ToThis:
case ToPrimitive:
+ case ToPropertyKey:
case NormalizeMapKey:
case AtomicsAdd:
case AtomicsAnd:
@@ -1431,6 +1439,18 @@
return type;
}
+ SpeculatedType resultOfToPropertyKey(SpeculatedType type)
+ {
+ // Propagate the prediction of the source directly if already proven to be a property key.
+ if (type && !(type & ~(SpecString | SpecSymbol)))
+ return type;
+
+ if (type & SpecStringObject && m_graph.canOptimizeStringObjectAccess(m_currentNode->origin.semantic))
+ return mergeSpeculations(type & SpecSymbol, SpecString);
+
+ return SpecString | SpecSymbol;
+ }
+
Vector<Node*> m_dependentNodes;
Node* m_currentNode;
bool m_changed { false };
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 203387b..ecdd993 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -361,6 +361,7 @@
case LogicalNot:
case CallObjectConstructor:
case ToPrimitive:
+ case ToPropertyKey:
case ToString:
case ToNumber:
case ToNumeric:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 68f523f..13f28ce 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -13053,6 +13053,30 @@
jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
}
+void SpeculativeJIT::compileToPropertyKey(Node* node)
+{
+ DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
+ JSValueOperand argument(this, node->child1());
+ JSValueRegsTemporary result(this, Reuse, argument);
+
+ JSValueRegs argumentRegs = argument.jsValueRegs();
+ JSValueRegs resultRegs = result.regs();
+
+ argument.use();
+
+ MacroAssembler::JumpList slowCases;
+ slowCases.append(m_jit.branchIfNotCell(argumentRegs));
+ MacroAssembler::Jump alreadyPropertyKey = m_jit.branchIfSymbol(argumentRegs.payloadGPR());
+ slowCases.append(m_jit.branchIfNotString(argumentRegs.payloadGPR()));
+
+ alreadyPropertyKey.link(&m_jit);
+ m_jit.moveValueRegs(argumentRegs, resultRegs);
+
+ addSlowPathGenerator(slowPathCall(slowCases, this, operationToPropertyKey, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argumentRegs));
+
+ jsValueResult(resultRegs, node, DataFormatJSCell, UseChildrenCalledExplicitly);
+}
+
void SpeculativeJIT::compileToNumeric(Node* node)
{
DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 8f96182..b1fb0e8 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1464,6 +1464,7 @@
void compileNewAsyncGenerator(Node*);
void compileNewArrayIterator(Node*);
void compileToPrimitive(Node*);
+ void compileToPropertyKey(Node*);
void compileToNumeric(Node*);
void compileLogShadowChickenPrologue(Node*);
void compileLogShadowChickenTail(Node*);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index d45edc1..fa066bf 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -3095,6 +3095,11 @@
break;
}
+ case ToPropertyKey: {
+ compileToPropertyKey(node);
+ break;
+ }
+
case ToNumber: {
JSValueOperand argument(this, node->child1());
GPRTemporary resultTag(this, Reuse, argument, TagWord);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index ec7f337..804369d 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -3431,6 +3431,11 @@
break;
}
+ case ToPropertyKey: {
+ compileToPropertyKey(node);
+ break;
+ }
+
case ToNumber: {
JSValueOperand argument(this, node->child1());
GPRTemporary result(this, Reuse, argument);
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index b953cfe..eba197f 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -233,6 +233,7 @@
case MultiGetByOffset:
case MultiPutByOffset:
case ToPrimitive:
+ case ToPropertyKey:
case Throw:
case ThrowStaticError:
case Unreachable:
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
index 58390d3..0c58572 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
@@ -1139,6 +1139,9 @@
case ToPrimitive:
compileToPrimitive();
break;
+ case ToPropertyKey:
+ compileToPropertyKey();
+ break;
case MakeRope:
compileMakeRope();
break;
@@ -7339,6 +7342,38 @@
m_out.appendTo(continuation, lastNext);
setJSValue(m_out.phi(Int64, results));
}
+
+ void compileToPropertyKey()
+ {
+ ASSERT(m_node->child1().useKind() == UntypedUse);
+ JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+ LValue value = lowJSValue(m_node->child1());
+
+ LBasicBlock isCellCase = m_out.newBlock();
+ LBasicBlock notStringCase = m_out.newBlock();
+ LBasicBlock slowPathCase = m_out.newBlock();
+ LBasicBlock continuation = m_out.newBlock();
+
+ Vector<ValueFromBlock, 3> results;
+ m_out.branch(
+ isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(slowPathCase));
+
+ LBasicBlock lastNext = m_out.appendTo(isCellCase, notStringCase);
+ results.append(m_out.anchor(value));
+ m_out.branch(isString(value, provenType(m_node->child1())), unsure(continuation), unsure(notStringCase));
+
+ m_out.appendTo(notStringCase, slowPathCase);
+ results.append(m_out.anchor(value));
+ m_out.branch(isSymbol(value, provenType(m_node->child1())), unsure(continuation), unsure(slowPathCase));
+
+ m_out.appendTo(slowPathCase, continuation);
+ results.append(m_out.anchor(vmCall(
+ Int64, operationToPropertyKey, weakPointer(globalObject), value)));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setJSValue(m_out.phi(Int64, results));
+ }
void compileMakeRope()
{