The StringFromCharCode DFG intrinsic should support untyped operands.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 13 Jan 2016 23:28:38 +0000 (23:28 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 13 Jan 2016 23:28:38 +0000 (23:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=153046

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

The current StringFromCharCode DFG intrinsic assumes that its operand charCode
must be an Int32.  This results in 26000+ BadType OSR exits in the LongSpider
crypto-aes benchmark.  With support for Untyped operands, the number of OSR
exits drops to 202.

* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileFromCharCode):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validate):
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::toUInt32):

LayoutTests:

* js/regress/ftl-polymorphic-StringFromCharCode-expected.txt: Added.
* js/regress/ftl-polymorphic-StringFromCharCode.html: Added.
* js/regress/script-tests/ftl-polymorphic-StringFromCharCode.js: Added.
(o1.valueOf):
(foo):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@194996 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/ChangeLog
LayoutTests/js/regress/ftl-polymorphic-StringFromCharCode-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/ftl-polymorphic-StringFromCharCode.html [new file with mode: 0644]
LayoutTests/js/regress/script-tests/ftl-polymorphic-StringFromCharCode.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGValidate.cpp
Source/JavaScriptCore/runtime/JSCJSValueInlines.h

index 37db46b..b2e20a5 100644 (file)
@@ -1,3 +1,16 @@
+2016-01-13  Mark Lam  <mark.lam@apple.com>
+
+        The StringFromCharCode DFG intrinsic should support untyped operands.
+        https://bugs.webkit.org/show_bug.cgi?id=153046
+
+        Reviewed by Geoffrey Garen.
+
+        * js/regress/ftl-polymorphic-StringFromCharCode-expected.txt: Added.
+        * js/regress/ftl-polymorphic-StringFromCharCode.html: Added.
+        * js/regress/script-tests/ftl-polymorphic-StringFromCharCode.js: Added.
+        (o1.valueOf):
+        (foo):
+
 2016-01-13  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Inspector should use the last sourceURL / sourceMappingURL directive
diff --git a/LayoutTests/js/regress/ftl-polymorphic-StringFromCharCode-expected.txt b/LayoutTests/js/regress/ftl-polymorphic-StringFromCharCode-expected.txt
new file mode 100644 (file)
index 0000000..e09d30c
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/ftl-polymorphic-StringFromCharCode
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/ftl-polymorphic-StringFromCharCode.html b/LayoutTests/js/regress/ftl-polymorphic-StringFromCharCode.html
new file mode 100644 (file)
index 0000000..0e34c7b
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/ftl-polymorphic-StringFromCharCode.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/script-tests/ftl-polymorphic-StringFromCharCode.js b/LayoutTests/js/regress/script-tests/ftl-polymorphic-StringFromCharCode.js
new file mode 100644 (file)
index 0000000..66e8cbb
--- /dev/null
@@ -0,0 +1,47 @@
+//@ runFTLNoCJIT
+var o1 = {
+    i: 65,
+    valueOf: function() { return this.i; }
+};
+
+result = 0;
+function foo(a) {
+    var result = String.fromCharCode(a);
+
+    // Busy work just to allow the DFG and FTL to optimize this. If the above causes
+    // us to speculation fail out to the baseline, this busy work will take a lot longer
+    // to run.
+    // This loop below also gets the DFG to compile this function sooner.
+    var count = 0;
+    for (var i = 0; i < 1000; i++)
+        count++;
+    return result + count;
+}
+noInline(foo);
+
+var iterations;
+var expectedResult;
+if (this.window) {
+    // The layout test doesn't like too many iterations and may time out.
+    iterations = 10000;
+    expectedResult = 10001;
+} else {
+    iterations = 100000;
+    expectedResult = 100001;
+}
+
+
+for (var i = 0; i <= iterations; i++) {
+    var resultStr;
+    if (i % 2 == 2)
+        resultStr = foo('65');
+    else if (i % 2 == 1)
+        resultStr = foo(o1);
+    else
+        resultStr = foo(65);
+    if (resultStr == 'A1000')
+        result++;
+}
+
+if (result != expectedResult)
+    throw "Bad result: " + result;
index c7b37ac..56ddc3d 100644 (file)
@@ -1,5 +1,32 @@
 2016-01-13  Mark Lam  <mark.lam@apple.com>
 
+        The StringFromCharCode DFG intrinsic should support untyped operands.
+        https://bugs.webkit.org/show_bug.cgi?id=153046
+
+        Reviewed by Geoffrey Garen.
+
+        The current StringFromCharCode DFG intrinsic assumes that its operand charCode
+        must be an Int32.  This results in 26000+ BadType OSR exits in the LongSpider
+        crypto-aes benchmark.  With support for Untyped operands, the number of OSR
+        exits drops to 202.
+
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileFromCharCode):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGValidate.cpp:
+        (JSC::DFG::Validate::validate):
+        * runtime/JSCJSValueInlines.h:
+        (JSC::JSValue::toUInt32):
+
+2016-01-13  Mark Lam  <mark.lam@apple.com>
+
         Use DFG Graph::binary/unaryArithShouldSpeculateInt32/MachineInt() functions consistently.
         https://bugs.webkit.org/show_bug.cgi?id=153080
 
index 72b24c7..343a6de 100644 (file)
@@ -135,7 +135,6 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case GetScope:
     case SkipScope:
     case StringCharCodeAt:
-    case StringFromCharCode:
     case CompareStrictEq:
     case IsUndefined:
     case IsBoolean:
@@ -258,6 +257,20 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         return;
     }
 
+    case StringFromCharCode:
+        switch (node->child1().useKind()) {
+        case Int32Use:
+            def(PureValue(node));
+            return;
+        case UntypedUse:
+            read(World);
+            write(Heap);
+            return;
+        default:
+            DFG_CRASH(graph, node, "Bad use kind");
+        }
+        return;
+
     case ArithAdd:
     case ArithNegate:
     case ArithMod:
index 3d58530..c9d5abf 100644 (file)
@@ -602,6 +602,10 @@ private:
         }
 
         case StringFromCharCode:
+            if (node->child1()->shouldSpeculateUntypedForArithmetic()) {
+                fixEdge<UntypedUse>(node->child1());
+                break;
+            }
             fixEdge<Int32Use>(node->child1());
             break;
 
index fc781eb..2fd5dbd 100644 (file)
@@ -1313,6 +1313,15 @@ JSCell* JIT_OPERATION operationStringFromCharCode(ExecState* exec, int32_t op1)
     return JSC::stringFromCharCode(exec, op1);
 }
 
+EncodedJSValue JIT_OPERATION operationStringFromCharCodeUntyped(ExecState* exec, EncodedJSValue encodedValue)
+{
+    VM* vm = &exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+    JSValue charValue = JSValue::decode(encodedValue);
+    int32_t chInt = charValue.toUInt32(exec);
+    return JSValue::encode(JSC::stringFromCharCode(exec, chInt));
+}
+
 int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue)
 {
     JSValue value = JSValue::decode(encodedValue);
index 5a48065..409629f 100644 (file)
@@ -38,6 +38,7 @@ struct OSRExitBase;
 extern "C" {
 
 JSCell* JIT_OPERATION operationStringFromCharCode(ExecState*, int32_t)  WTF_INTERNAL; 
+EncodedJSValue JIT_OPERATION operationStringFromCharCodeUntyped(ExecState*, EncodedJSValue)  WTF_INTERNAL;
 
 // These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
 JSCell* JIT_OPERATION operationCreateThis(ExecState*, JSObject* constructor, int32_t inlineCapacity) WTF_INTERNAL;
index bbabe26..ccce791 100755 (executable)
@@ -1871,7 +1871,27 @@ void SpeculativeJIT::compileGetByValOnString(Node* node)
 
 void SpeculativeJIT::compileFromCharCode(Node* node)
 {
-    SpeculateStrictInt32Operand property(this, node->child1());
+    Edge& child = node->child1();
+    if (child.useKind() == UntypedUse) {
+        JSValueOperand opr(this, child);
+        JSValueRegs oprRegs = opr.jsValueRegs();
+#if USE(JSVALUE64)
+        GPRTemporary result(this);
+        JSValueRegs resultRegs = JSValueRegs(result.gpr());
+#else
+        GPRTemporary resultTag(this);
+        GPRTemporary resultPayload(this);
+        JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
+#endif
+        flushRegisters();
+        callOperation(operationStringFromCharCodeUntyped, resultRegs, oprRegs);
+        m_jit.exceptionCheck();
+        
+        jsValueResult(resultRegs, node);
+        return;
+    }
+
+    SpeculateStrictInt32Operand property(this, child);
     GPRReg propertyReg = property.gpr();
     GPRTemporary smallStrings(this);
     GPRTemporary scratch(this);
index 0322bb7..5312c8d 100755 (executable)
@@ -1409,6 +1409,10 @@ public:
         m_jit.setupArgumentsWithExecState(arg1);
         return appendCallSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(J_JITOperation_EJ operation, JSValueRegs result, JSValueRegs arg1)
+    {
+        return callOperation(operation, result.payloadGPR(), arg1.payloadGPR());
+    }
     JITCompiler::Call callOperation(J_JITOperation_EJ operation, GPRReg result, GPRReg arg1)
     {
         m_jit.setupArgumentsWithExecState(arg1);
@@ -1610,6 +1614,10 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2);
         return appendCallSetResult(operation, resultPayload, resultTag);
     }
+    JITCompiler::Call callOperation(J_JITOperation_EJ operation, JSValueRegs result, JSValueRegs arg1)
+    {
+        return callOperation(operation, result.tagGPR(), result.payloadGPR(), arg1.tagGPR(), arg1.payloadGPR());
+    }
     JITCompiler::Call callOperation(J_JITOperation_EJ operation, GPRReg resultPayload, GPRReg resultTag, GPRReg arg1)
     {
         m_jit.setupArgumentsWithExecState(arg1);
index de68e63..3fe1da2 100644 (file)
@@ -264,6 +264,7 @@ public:
                     VALIDATE((node), !!node->child2());
                     break;
                 case CheckStructure:
+                case StringFromCharCode:
                     VALIDATE((node), !!node->child1());
                     break;
                 case PutStructure:
index c8f1f08..2bff86b 100644 (file)
@@ -46,7 +46,7 @@ ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
 
 inline uint32_t JSValue::toUInt32(ExecState* exec) const
 {
-    // See comment on JSC::toUInt32, above.
+    // See comment on JSC::toUInt32, in JSCJSValue.h.
     return toInt32(exec);
 }