Diff
Modified: trunk/JSTests/ChangeLog (221782 => 221783)
--- trunk/JSTests/ChangeLog 2017-09-08 10:57:35 UTC (rev 221782)
+++ trunk/JSTests/ChangeLog 2017-09-08 15:36:05 UTC (rev 221783)
@@ -1,3 +1,21 @@
+2017-09-08 Yusuke Suzuki <[email protected]>
+
+ [DFG][FTL] GetByVal(ObjectUse with Array::Generic, StringUse/SymbolUse) should be supported
+ https://bugs.webkit.org/show_bug.cgi?id=176590
+
+ Reviewed by Saam Barati.
+
+ * microbenchmarks/object-iterate-symbols.js: Added.
+ (test):
+ * microbenchmarks/object-iterate.js: Added.
+ (test):
+ * stress/object-iterate-symbols.js: Added.
+ (shouldBe):
+ (test):
+ * stress/object-iterate.js: Added.
+ (shouldBe):
+ (test):
+
2017-09-07 Per Arne Vollan <[email protected]>
[Win32] 10 JSC stress tests are failing.
Added: trunk/JSTests/microbenchmarks/object-iterate-symbols.js (0 => 221783)
--- trunk/JSTests/microbenchmarks/object-iterate-symbols.js (rev 0)
+++ trunk/JSTests/microbenchmarks/object-iterate-symbols.js 2017-09-08 15:36:05 UTC (rev 221783)
@@ -0,0 +1,27 @@
+var a = Symbol("a");
+var b = Symbol("b");
+var c = Symbol("c");
+var d = Symbol("d");
+var e = Symbol("e");
+
+var obj = {
+ [a]: 1,
+ [b]: 2,
+ [c]: 3,
+ [d]: null,
+ [e]: 'e'
+};
+
+function test(src) {
+ var array = [];
+ var keys = Object.getOwnPropertySymbols(src);
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ array.push(src[key]);
+ }
+ return array;
+}
+noInline(test);
+
+for (var i = 0; i < 1e4; ++i)
+ test(obj);
Added: trunk/JSTests/microbenchmarks/object-iterate.js (0 => 221783)
--- trunk/JSTests/microbenchmarks/object-iterate.js (rev 0)
+++ trunk/JSTests/microbenchmarks/object-iterate.js 2017-09-08 15:36:05 UTC (rev 221783)
@@ -0,0 +1,21 @@
+var obj = {
+ a: 1,
+ b: 2,
+ c: 3,
+ d: null,
+ e: 'e'
+};
+
+function test(src) {
+ var array = [];
+ var keys = Object.keys(src);
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ array.push(src[key]);
+ }
+ return array;
+}
+noInline(test);
+
+for (var i = 0; i < 1e4; ++i)
+ test(obj);
Added: trunk/JSTests/stress/object-iterate-symbols.js (0 => 221783)
--- trunk/JSTests/stress/object-iterate-symbols.js (rev 0)
+++ trunk/JSTests/stress/object-iterate-symbols.js 2017-09-08 15:36:05 UTC (rev 221783)
@@ -0,0 +1,32 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+var a = Symbol("a");
+var b = Symbol("b");
+var c = Symbol("c");
+var d = Symbol("d");
+var e = Symbol("e");
+
+var obj = {
+ [a]: 1,
+ [b]: 2,
+ [c]: 3,
+ [d]: null,
+ [e]: 'e'
+};
+
+function test(src) {
+ var array = [];
+ var keys = Object.getOwnPropertySymbols(src);
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ array.push(src[key]);
+ }
+ return array;
+}
+noInline(test);
+
+for (var i = 0; i < 1e4; ++i)
+ shouldBe(JSON.stringify(test(obj)), `[1,2,3,null,"e"]`);
Added: trunk/JSTests/stress/object-iterate.js (0 => 221783)
--- trunk/JSTests/stress/object-iterate.js (rev 0)
+++ trunk/JSTests/stress/object-iterate.js 2017-09-08 15:36:05 UTC (rev 221783)
@@ -0,0 +1,26 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+var obj = {
+ a: 1,
+ b: 2,
+ c: 3,
+ d: null,
+ e: 'e'
+};
+
+function test(src) {
+ var array = [];
+ var keys = Object.keys(src);
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ array.push(src[key]);
+ }
+ return array;
+}
+noInline(test);
+
+for (var i = 0; i < 1e4; ++i)
+ shouldBe(JSON.stringify(test(obj)), `[1,2,3,null,"e"]`);
Modified: trunk/Source/_javascript_Core/ChangeLog (221782 => 221783)
--- trunk/Source/_javascript_Core/ChangeLog 2017-09-08 10:57:35 UTC (rev 221782)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-09-08 15:36:05 UTC (rev 221783)
@@ -1,3 +1,33 @@
+2017-09-08 Yusuke Suzuki <[email protected]>
+
+ [DFG][FTL] GetByVal(ObjectUse with Array::Generic, StringUse/SymbolUse) should be supported
+ https://bugs.webkit.org/show_bug.cgi?id=176590
+
+ Reviewed by Saam Barati.
+
+ We add fixup edges for GetByVal(Array::Generic) to call faster operation instead of generic operationGetByVal.
+
+ baseline patched
+
+ object-iterate 5.8531+-0.3029 5.7903+-0.2795 might be 1.0108x faster
+ object-iterate-symbols 7.4099+-0.3993 ^ 5.8254+-0.2276 ^ definitely 1.2720x faster
+
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGOperations.cpp:
+ (JSC::DFG::getByValObject):
+ * dfg/DFGOperations.h:
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileGetByValForObjectWithString):
+ (JSC::DFG::SpeculativeJIT::compileGetByValForObjectWithSymbol):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
+
2017-09-07 Mark Lam <[email protected]>
Use JIT probes for DFG OSR exit.
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (221782 => 221783)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2017-09-08 10:57:35 UTC (rev 221782)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2017-09-08 15:36:05 UTC (rev 221783)
@@ -788,6 +788,19 @@
RELEASE_ASSERT_NOT_REACHED();
break;
case Array::Generic:
+ if (node->child1()->shouldSpeculateObject()) {
+ if (node->child2()->shouldSpeculateString()) {
+ fixEdge<ObjectUse>(node->child1());
+ fixEdge<StringUse>(node->child2());
+ break;
+ }
+
+ if (node->child2()->shouldSpeculateSymbol()) {
+ fixEdge<ObjectUse>(node->child1());
+ fixEdge<SymbolUse>(node->child2());
+ break;
+ }
+ }
#if USE(JSVALUE32_64)
fixEdge<CellUse>(node->child1()); // Speculating cell due to register pressure on 32-bit.
#endif
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (221782 => 221783)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2017-09-08 10:57:35 UTC (rev 221782)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2017-09-08 15:36:05 UTC (rev 221783)
@@ -184,6 +184,16 @@
return JSValue::encode(jsNumber(input));
}
+ALWAYS_INLINE static JSValue getByValObject(ExecState* exec, VM& vm, JSObject* base, PropertyName propertyName)
+{
+ Structure& structure = *base->structure(vm);
+ if (JSCell::canUseFastGetOwnProperty(structure)) {
+ if (JSValue result = base->fastGetOwnProperty(vm, structure, propertyName))
+ return result;
+ }
+ return base->get(exec, propertyName);
+}
+
extern "C" {
EncodedJSValue JIT_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp)
@@ -584,6 +594,28 @@
return getByValCellInt(exec, base, index);
}
+EncodedJSValue JIT_OPERATION operationGetByValObjectString(ExecState* exec, JSCell* base, JSCell* string)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto propertyName = asString(string)->toIdentifier(exec);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+ scope.release();
+ return JSValue::encode(getByValObject(exec, vm, asObject(base), propertyName));
+}
+
+EncodedJSValue JIT_OPERATION operationGetByValObjectSymbol(ExecState* exec, JSCell* base, JSCell* symbol)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ return JSValue::encode(getByValObject(exec, vm, asObject(base), asSymbol(symbol)->privateName()));
+}
+
void JIT_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
{
VM* vm = &exec->vm();
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (221782 => 221783)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2017-09-08 10:57:35 UTC (rev 221782)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2017-09-08 15:36:05 UTC (rev 221783)
@@ -71,6 +71,8 @@
EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationGetByValObjectInt(ExecState*, JSObject*, int32_t) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState*, JSString*, int32_t) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByValObjectString(ExecState*, JSCell*, JSCell* string) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByValObjectSymbol(ExecState*, JSCell*, JSCell* symbol) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationToNumber(ExecState*, EncodedJSValue) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationGetByIdWithThis(ExecState*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (221782 => 221783)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2017-09-08 10:57:35 UTC (rev 221782)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2017-09-08 15:36:05 UTC (rev 221783)
@@ -3144,6 +3144,62 @@
noResult(node);
}
+void SpeculativeJIT::compileGetByValForObjectWithString(Node* node)
+{
+ SpeculateCellOperand arg1(this, node->child1());
+ SpeculateCellOperand arg2(this, node->child2());
+
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+
+ speculateObject(node->child1(), arg1GPR);
+ speculateString(node->child2(), arg2GPR);
+
+ GPRFlushedCallResult resultPayload(this);
+ GPRReg resultPayloadGPR = resultPayload.gpr();
+#if USE(JSVALUE64)
+ JSValueRegs resultRegs(resultPayloadGPR);
+#else
+ GPRFlushedCallResult2 resultTag(this);
+ GPRReg resultTagGPR = resultTag.gpr();
+ JSValueRegs resultRegs(resultTagGPR, resultPayloadGPR);
+#endif
+
+ flushRegisters();
+ callOperation(operationGetByValObjectString, extractResult(resultRegs), arg1GPR, arg2GPR);
+ m_jit.exceptionCheck();
+
+ jsValueResult(resultRegs, node);
+}
+
+void SpeculativeJIT::compileGetByValForObjectWithSymbol(Node* node)
+{
+ SpeculateCellOperand arg1(this, node->child1());
+ SpeculateCellOperand arg2(this, node->child2());
+
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+
+ speculateObject(node->child1(), arg1GPR);
+ speculateSymbol(node->child2(), arg2GPR);
+
+ GPRFlushedCallResult resultPayload(this);
+ GPRReg resultPayloadGPR = resultPayload.gpr();
+#if USE(JSVALUE64)
+ JSValueRegs resultRegs(resultPayloadGPR);
+#else
+ GPRFlushedCallResult2 resultTag(this);
+ GPRReg resultTagGPR = resultTag.gpr();
+ JSValueRegs resultRegs(resultTagGPR, resultPayloadGPR);
+#endif
+
+ flushRegisters();
+ callOperation(operationGetByValObjectSymbol, extractResult(resultRegs), arg1GPR, arg2GPR);
+ m_jit.exceptionCheck();
+
+ jsValueResult(resultRegs, node);
+}
+
void SpeculativeJIT::compileInstanceOfForObject(Node*, GPRReg valueReg, GPRReg prototypeReg, GPRReg scratchReg, GPRReg scratch2Reg)
{
// Check that prototype is an object.
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (221782 => 221783)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2017-09-08 10:57:35 UTC (rev 221782)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2017-09-08 15:36:05 UTC (rev 221783)
@@ -2873,6 +2873,8 @@
void compilePutByValForIntTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType);
void compileGetByValOnFloatTypedArray(Node*, TypedArrayType);
void compilePutByValForFloatTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType);
+ void compileGetByValForObjectWithString(Node*);
+ void compileGetByValForObjectWithSymbol(Node*);
// If this returns false it means that we terminated speculative execution.
bool getIntTypedArrayStoreOperand(
GPRTemporary& value,
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (221782 => 221783)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2017-09-08 10:57:35 UTC (rev 221782)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2017-09-08 15:36:05 UTC (rev 221783)
@@ -2593,6 +2593,18 @@
break;
}
case Array::Generic: {
+ if (node->child1().useKind() == ObjectUse) {
+ if (node->child2().useKind() == StringUse) {
+ compileGetByValForObjectWithString(node);
+ break;
+ }
+
+ if (node->child2().useKind() == SymbolUse) {
+ compileGetByValForObjectWithSymbol(node);
+ break;
+ }
+ }
+
SpeculateCellOperand base(this, node->child1()); // Save a register, speculate cell. We'll probably be right.
JSValueOperand property(this, node->child2());
GPRReg baseGPR = base.gpr();
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (221782 => 221783)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2017-09-08 10:57:35 UTC (rev 221782)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2017-09-08 15:36:05 UTC (rev 221783)
@@ -2729,6 +2729,17 @@
break;
}
case Array::Generic: {
+ if (node->child1().useKind() == ObjectUse) {
+ if (node->child2().useKind() == StringUse) {
+ compileGetByValForObjectWithString(node);
+ break;
+ }
+
+ if (node->child2().useKind() == SymbolUse) {
+ compileGetByValForObjectWithSymbol(node);
+ break;
+ }
+ }
JSValueOperand base(this, node->child1());
JSValueOperand property(this, node->child2());
GPRReg baseGPR = base.gpr();
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (221782 => 221783)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2017-09-08 10:57:35 UTC (rev 221782)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2017-09-08 15:36:05 UTC (rev 221783)
@@ -3673,6 +3673,21 @@
}
case Array::Generic: {
+ if (m_node->child1().useKind() == ObjectUse) {
+ if (m_node->child2().useKind() == StringUse) {
+ setJSValue(vmCall(
+ Int64, m_out.operation(operationGetByValObjectString), m_callFrame,
+ lowObject(m_node->child1()), lowString(m_node->child2())));
+ return;
+ }
+
+ if (m_node->child2().useKind() == SymbolUse) {
+ setJSValue(vmCall(
+ Int64, m_out.operation(operationGetByValObjectSymbol), m_callFrame,
+ lowObject(m_node->child1()), lowSymbol(m_node->child2())));
+ return;
+ }
+ }
setJSValue(vmCall(
Int64, m_out.operation(operationGetByVal), m_callFrame,
lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));