Diff
Modified: branches/safari-612.1.23-branch/JSTests/ChangeLog (279746 => 279747)
--- branches/safari-612.1.23-branch/JSTests/ChangeLog 2021-07-08 20:27:16 UTC (rev 279746)
+++ branches/safari-612.1.23-branch/JSTests/ChangeLog 2021-07-08 20:27:22 UTC (rev 279747)
@@ -1,5 +1,56 @@
2021-07-08 Ruben Turcios <rubent...@apple.com>
+ Cherry-pick r279690. rdar://problem/80339399
+
+ [JSC] Fix Object.assign fast path to accept undefined/null
+ https://bugs.webkit.org/show_bug.cgi?id=227769
+ rdar://80264271
+
+ Reviewed by Saam Barati.
+
+ JSTests:
+
+ * stress/object-assign-undefined.js: Added.
+ (test):
+
+ Source/_javascript_Core:
+
+ Object.assign can accept undefined or null as a second (or latter) parameters.
+ If it is passed, the parameter is just ignored. Previous DFG / FTL optimization patch
+ does not handle this case.
+
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGOperations.cpp:
+ (JSC::DFG::JSC_DEFINE_JIT_OPERATION):
+ * dfg/DFGOperations.h:
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileObjectAssign):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileObjectAssign):
+ * runtime/ObjectConstructor.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/ObjectConstructorInlines.h:
+ (JSC::objectAssignFast):
+
+
+ git-svn-id: https://svn.webkit.org/repository/webkit/trunk@279690 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+ 2021-07-07 Yusuke Suzuki <ysuz...@apple.com>
+
+ [JSC] Fix Object.assign fast path to accept undefined/null
+ https://bugs.webkit.org/show_bug.cgi?id=227769
+ rdar://80264271
+
+ Reviewed by Saam Barati.
+
+ * stress/object-assign-undefined.js: Added.
+ (test):
+
+2021-07-08 Ruben Turcios <rubent...@apple.com>
+
Cherry-pick r279604. rdar://problem/80340434
[JSC] Optimize Object.assign and putDirectInternal
Added: branches/safari-612.1.23-branch/JSTests/stress/object-assign-undefined.js (0 => 279747)
--- branches/safari-612.1.23-branch/JSTests/stress/object-assign-undefined.js (rev 0)
+++ branches/safari-612.1.23-branch/JSTests/stress/object-assign-undefined.js 2021-07-08 20:27:22 UTC (rev 279747)
@@ -0,0 +1,14 @@
+function test(target, source)
+{
+ Object.assign(target, source);
+}
+noInline(test);
+
+test({}, undefined);
+test({}, null);
+for (var i = 0; i < 1e4; ++i)
+ test({}, {});
+test({}, undefined);
+test({}, null);
+for (var i = 0; i < 1e4; ++i)
+ test({}, undefined);
Modified: branches/safari-612.1.23-branch/Source/_javascript_Core/ChangeLog (279746 => 279747)
--- branches/safari-612.1.23-branch/Source/_javascript_Core/ChangeLog 2021-07-08 20:27:16 UTC (rev 279746)
+++ branches/safari-612.1.23-branch/Source/_javascript_Core/ChangeLog 2021-07-08 20:27:22 UTC (rev 279747)
@@ -1,5 +1,73 @@
2021-07-08 Ruben Turcios <rubent...@apple.com>
+ Cherry-pick r279690. rdar://problem/80339399
+
+ [JSC] Fix Object.assign fast path to accept undefined/null
+ https://bugs.webkit.org/show_bug.cgi?id=227769
+ rdar://80264271
+
+ Reviewed by Saam Barati.
+
+ JSTests:
+
+ * stress/object-assign-undefined.js: Added.
+ (test):
+
+ Source/_javascript_Core:
+
+ Object.assign can accept undefined or null as a second (or latter) parameters.
+ If it is passed, the parameter is just ignored. Previous DFG / FTL optimization patch
+ does not handle this case.
+
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGOperations.cpp:
+ (JSC::DFG::JSC_DEFINE_JIT_OPERATION):
+ * dfg/DFGOperations.h:
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileObjectAssign):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileObjectAssign):
+ * runtime/ObjectConstructor.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/ObjectConstructorInlines.h:
+ (JSC::objectAssignFast):
+
+
+ git-svn-id: https://svn.webkit.org/repository/webkit/trunk@279690 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+ 2021-07-07 Yusuke Suzuki <ysuz...@apple.com>
+
+ [JSC] Fix Object.assign fast path to accept undefined/null
+ https://bugs.webkit.org/show_bug.cgi?id=227769
+ rdar://80264271
+
+ Reviewed by Saam Barati.
+
+ Object.assign can accept undefined or null as a second (or latter) parameters.
+ If it is passed, the parameter is just ignored. Previous DFG / FTL optimization patch
+ does not handle this case.
+
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGOperations.cpp:
+ (JSC::DFG::JSC_DEFINE_JIT_OPERATION):
+ * dfg/DFGOperations.h:
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileObjectAssign):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileObjectAssign):
+ * runtime/ObjectConstructor.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/ObjectConstructorInlines.h:
+ (JSC::objectAssignFast):
+
+2021-07-08 Ruben Turcios <rubent...@apple.com>
+
Cherry-pick r279604. rdar://problem/80340434
[JSC] Optimize Object.assign and putDirectInternal
Modified: branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (279746 => 279747)
--- branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2021-07-08 20:27:16 UTC (rev 279746)
+++ branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2021-07-08 20:27:22 UTC (rev 279747)
@@ -2943,10 +2943,7 @@
Node* target = addToGraph(ToObject, OpInfo(errorStringIndex), OpInfo(SpecNone), get(virtualRegisterForArgumentIncludingThis(1, registerOffset)));
m_exitOK = true;
addToGraph(ExitOK);
- Node* source = addToGraph(ToObject, OpInfo(errorStringIndex), OpInfo(SpecNone), get(virtualRegisterForArgumentIncludingThis(2, registerOffset)));
- m_exitOK = true;
- addToGraph(ExitOK);
- addToGraph(ObjectAssign, Edge(target, KnownCellUse), Edge(source, KnownCellUse));
+ addToGraph(ObjectAssign, Edge(target, KnownCellUse), Edge(get(virtualRegisterForArgumentIncludingThis(2, registerOffset))));
setResult(target);
return true;
}
Modified: branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (279746 => 279747)
--- branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2021-07-08 20:27:16 UTC (rev 279746)
+++ branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2021-07-08 20:27:22 UTC (rev 279747)
@@ -2800,6 +2800,15 @@
break;
}
+ case ObjectAssign: {
+ Edge& source = node->child2();
+ if (source->shouldSpeculateObject())
+ fixEdge<ObjectUse>(source);
+ else
+ fixEdge<UntypedUse>(source);
+ break;
+ }
+
#if ASSERT_ENABLED
// Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
case SetArgumentDefinitely:
@@ -2892,7 +2901,6 @@
case FilterSetPrivateBrandStatus:
case InvalidationPoint:
case CreateArgumentsButterfly:
- case ObjectAssign:
break;
#else // not ASSERT_ENABLED
default:
Modified: branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGOperations.cpp (279746 => 279747)
--- branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGOperations.cpp 2021-07-08 20:27:16 UTC (rev 279746)
+++ branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGOperations.cpp 2021-07-08 20:27:22 UTC (rev 279747)
@@ -310,7 +310,6 @@
CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
auto scope = DECLARE_THROW_SCOPE(vm);
-
bool targetCanPerformFastPut = jsDynamicCast<JSFinalObject*>(vm, target) && target->canPerformFastPutInlineExcludingProto(vm) && target->isStructureExtensible(vm);
if (targetCanPerformFastPut) {
@@ -366,6 +365,38 @@
objectAssignGeneric(globalObject, vm, target, source);
}
+JSC_DEFINE_JIT_OPERATION(operationObjectAssignUntyped, void, (JSGlobalObject* globalObject, JSObject* target, EncodedJSValue encodedSource))
+{
+ VM& vm = globalObject->vm();
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ bool targetCanPerformFastPut = jsDynamicCast<JSFinalObject*>(vm, target) && target->canPerformFastPutInlineExcludingProto(vm) && target->isStructureExtensible(vm);
+
+ JSValue sourceValue = JSValue::decode(encodedSource);
+ if (sourceValue.isUndefinedOrNull())
+ return;
+ JSObject* source = sourceValue.toObject(globalObject);
+ RETURN_IF_EXCEPTION(scope, void());
+
+ if (targetCanPerformFastPut) {
+ if (!source->staticPropertiesReified(vm)) {
+ source->reifyAllStaticProperties(globalObject);
+ RETURN_IF_EXCEPTION(scope, void());
+ }
+
+ if (canPerformFastPropertyEnumerationForObjectAssign(source->structure(vm))) {
+ Vector<RefPtr<UniquedStringImpl>, 8> properties;
+ MarkedArgumentBuffer values;
+ objectAssignFast(vm, target, source, properties, values);
+ return;
+ }
+ }
+
+ objectAssignGeneric(globalObject, vm, target, source);
+}
+
JSC_DEFINE_JIT_OPERATION(operationCreateThis, JSCell*, (JSGlobalObject* globalObject, JSObject* constructor, uint32_t inlineCapacity))
{
VM& vm = globalObject->vm();
Modified: branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGOperations.h (279746 => 279747)
--- branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGOperations.h 2021-07-08 20:27:16 UTC (rev 279746)
+++ branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGOperations.h 2021-07-08 20:27:22 UTC (rev 279747)
@@ -54,6 +54,7 @@
JSC_DECLARE_JIT_OPERATION(operationObjectCreate, JSCell*, (JSGlobalObject*, EncodedJSValue));
JSC_DECLARE_JIT_OPERATION(operationObjectCreateObject, JSCell*, (JSGlobalObject*, JSObject*));
JSC_DECLARE_JIT_OPERATION(operationObjectAssignObject, void, (JSGlobalObject*, JSObject*, JSObject*));
+JSC_DECLARE_JIT_OPERATION(operationObjectAssignUntyped, void, (JSGlobalObject*, JSObject*, EncodedJSValue));
JSC_DECLARE_JIT_OPERATION(operationCreateThis, JSCell*, (JSGlobalObject*, JSObject* constructor, uint32_t inlineCapacity));
JSC_DECLARE_JIT_OPERATION(operationCreatePromise, JSCell*, (JSGlobalObject*, JSObject* constructor));
JSC_DECLARE_JIT_OPERATION(operationCreateInternalPromise, JSCell*, (JSGlobalObject*, JSObject* constructor));
Modified: branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (279746 => 279747)
--- branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-07-08 20:27:16 UTC (rev 279746)
+++ branches/safari-612.1.23-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-07-08 20:27:22 UTC (rev 279747)
@@ -14052,16 +14052,40 @@
void SpeculativeJIT::compileObjectAssign(Node* node)
{
SpeculateCellOperand target(this, node->child1());
- SpeculateCellOperand source(this, node->child2());
- GPRReg targetGPR = target.gpr();
- GPRReg sourceGPR = source.gpr();
+ switch (node->child2().useKind()) {
+ case ObjectUse: {
+ SpeculateCellOperand source(this, node->child2());
- flushRegisters();
- callOperation(operationObjectAssignObject, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), targetGPR, sourceGPR);
- m_jit.exceptionCheck();
+ GPRReg targetGPR = target.gpr();
+ GPRReg sourceGPR = source.gpr();
- noResult(node);
+ speculateObject(node->child2(), sourceGPR);
+
+ flushRegisters();
+ callOperation(operationObjectAssignObject, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), targetGPR, sourceGPR);
+ m_jit.exceptionCheck();
+
+ noResult(node);
+ return;
+ }
+ case UntypedUse: {
+ JSValueOperand source(this, node->child2());
+
+ GPRReg targetGPR = target.gpr();
+ JSValueRegs sourceRegs = source.jsValueRegs();
+
+ flushRegisters();
+ callOperation(operationObjectAssignUntyped, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), targetGPR, sourceRegs);
+ m_jit.exceptionCheck();
+
+ noResult(node);
+ return;
+ }
+ default:
+ DFG_CRASH(m_jit.graph(), node, "Bad use kind");
+ return;
+ }
}
void SpeculativeJIT::compileObjectCreate(Node* node)
Modified: branches/safari-612.1.23-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (279746 => 279747)
--- branches/safari-612.1.23-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2021-07-08 20:27:16 UTC (rev 279746)
+++ branches/safari-612.1.23-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2021-07-08 20:27:22 UTC (rev 279747)
@@ -7082,7 +7082,17 @@
void compileObjectAssign()
{
JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
- vmCall(Void, operationObjectAssignObject, weakPointer(globalObject), lowCell(m_node->child1()), lowCell(m_node->child2()));
+ switch (m_node->child2().useKind()) {
+ case ObjectUse:
+ vmCall(Void, operationObjectAssignObject, weakPointer(globalObject), lowCell(m_node->child1()), lowObject(m_node->child2()));
+ return;
+ case UntypedUse:
+ vmCall(Void, operationObjectAssignUntyped, weakPointer(globalObject), lowCell(m_node->child1()), lowJSValue(m_node->child2()));
+ return;
+ default:
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
+ return;
+ }
}
void compileObjectCreate()
Modified: branches/safari-612.1.23-branch/Source/_javascript_Core/runtime/ObjectConstructor.cpp (279746 => 279747)
--- branches/safari-612.1.23-branch/Source/_javascript_Core/runtime/ObjectConstructor.cpp 2021-07-08 20:27:16 UTC (rev 279746)
+++ branches/safari-612.1.23-branch/Source/_javascript_Core/runtime/ObjectConstructor.cpp 2021-07-08 20:27:22 UTC (rev 279747)
@@ -333,42 +333,7 @@
}
if (canPerformFastPropertyEnumerationForObjectAssign(source->structure(vm))) {
- // |source| Structure does not have any getters. And target can perform fast put.
- // So enumerating properties and putting properties are non observable.
-
- // FIXME: It doesn't seem like we should have to do this in two phases, but
- // we're running into crashes where it appears that source is transitioning
- // under us, and even ends up in a state where it has a null butterfly. My
- // leading hypothesis here is that we fire some value replacement watchpoint
- // that ends up transitioning the structure underneath us.
- // https://bugs.webkit.org/show_bug.cgi?id=187837
-
- // FIXME: This fast path is very similar to DFGOperations' one. But extracting it to a function caused performance
- // regression in object-assign-replace. Since the code is small and fast path, we keep both.
-
- // Do not clear since Vector::clear shrinks the backing store.
- properties.resize(0);
- values.clear();
- source->structure(vm)->forEachProperty(vm, [&] (const PropertyMapEntry& entry) -> bool {
- if (entry.attributes & PropertyAttribute::DontEnum)
- return true;
-
- PropertyName propertyName(entry.key);
- if (propertyName.isPrivateName())
- return true;
-
- properties.append(entry.key);
- values.appendWithCrashOnOverflow(source->getDirect(entry.offset));
-
- return true;
- });
-
- for (size_t i = 0; i < properties.size(); ++i) {
- // FIXME: We could put properties in a batching manner to accelerate Object.assign more.
- // https://bugs.webkit.org/show_bug.cgi?id=185358
- PutPropertySlot putPropertySlot(target, true);
- target->putOwnDataProperty(vm, properties[i].get(), values.at(i), putPropertySlot);
- }
+ objectAssignFast(vm, target, source, properties, values);
continue;
}
}
Modified: branches/safari-612.1.23-branch/Source/_javascript_Core/runtime/ObjectConstructorInlines.h (279746 => 279747)
--- branches/safari-612.1.23-branch/Source/_javascript_Core/runtime/ObjectConstructorInlines.h 2021-07-08 20:27:16 UTC (rev 279746)
+++ branches/safari-612.1.23-branch/Source/_javascript_Core/runtime/ObjectConstructorInlines.h 2021-07-08 20:27:22 UTC (rev 279747)
@@ -53,4 +53,45 @@
return true;
}
+ALWAYS_INLINE void objectAssignFast(VM& vm, JSObject* target, JSObject* source, Vector<RefPtr<UniquedStringImpl>, 8>& properties, MarkedArgumentBuffer& values)
+{
+ // |source| Structure does not have any getters. And target can perform fast put.
+ // So enumerating properties and putting properties are non observable.
+
+ // FIXME: It doesn't seem like we should have to do this in two phases, but
+ // we're running into crashes where it appears that source is transitioning
+ // under us, and even ends up in a state where it has a null butterfly. My
+ // leading hypothesis here is that we fire some value replacement watchpoint
+ // that ends up transitioning the structure underneath us.
+ // https://bugs.webkit.org/show_bug.cgi?id=187837
+
+ // FIXME: This fast path is very similar to ObjectConstructor' one. But extracting it to a function caused performance
+ // regression in object-assign-replace. Since the code is small and fast path, we keep both.
+
+ // Do not clear since Vector::clear shrinks the backing store.
+ properties.resize(0);
+ values.clear();
+ source->structure(vm)->forEachProperty(vm, [&] (const PropertyMapEntry& entry) -> bool {
+ if (entry.attributes & PropertyAttribute::DontEnum)
+ return true;
+
+ PropertyName propertyName(entry.key);
+ if (propertyName.isPrivateName())
+ return true;
+
+ properties.append(entry.key);
+ values.appendWithCrashOnOverflow(source->getDirect(entry.offset));
+
+ return true;
+ });
+
+ for (size_t i = 0; i < properties.size(); ++i) {
+ // FIXME: We could put properties in a batching manner to accelerate Object.assign more.
+ // https://bugs.webkit.org/show_bug.cgi?id=185358
+ PutPropertySlot putPropertySlot(target, true);
+ target->putOwnDataProperty(vm, properties[i].get(), values.at(i), putPropertySlot);
+ }
+}
+
+
} // namespace JSC