Bug 135593

Summary: Using +s to convert a string to a number badly confuses the DFG
Product: WebKit Reporter: Mark Hahnenberg <mhahnenberg>
Component: JavaScriptCoreAssignee: Mark Hahnenberg <mhahnenb>
Status: NEW    
Severity: Normal CC: fpizlo, mhahnenb
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
profiler output
none
graph dump
none
huffman benchmark
none
huffman benchmark
none
Patch
none
Patch
none
Patch fpizlo: review+

Mark Hahnenberg
Reported 2014-08-04 21:27:40 PDT
I was writing a toy Huffman encoder/decoder in JS, and I was comparing the performance of JSC to nodejs. I ran the benchmark by hooking it into the octane harness. nodejs crushes JSC on this particular benchmark (by like 10x). I was curious and ran the profiler, and I noticed a very simple function was exiting a ton. Here's the source of the function: function (i) { return +i; } I'll attach the profiler output separately.
Attachments
profiler output (37.60 KB, text/plain)
2014-08-04 21:29 PDT, Mark Hahnenberg
no flags
graph dump (129.85 KB, text/plain)
2014-08-04 21:29 PDT, Mark Hahnenberg
no flags
huffman benchmark (11.95 KB, application/javascript)
2014-08-04 21:30 PDT, Mark Hahnenberg
no flags
huffman benchmark (8.67 KB, application/javascript)
2014-08-04 21:33 PDT, Mark Hahnenberg
no flags
Patch (11.04 KB, patch)
2014-08-05 15:27 PDT, Mark Hahnenberg
no flags
Patch (14.77 KB, patch)
2014-08-06 14:15 PDT, Mark Hahnenberg
no flags
Patch (14.90 KB, patch)
2014-08-08 14:20 PDT, Mark Hahnenberg
fpizlo: review+
Mark Hahnenberg
Comment 1 2014-08-04 21:29:08 PDT
Created attachment 236001 [details] profiler output
Mark Hahnenberg
Comment 2 2014-08-04 21:29:39 PDT
Created attachment 236002 [details] graph dump
Mark Hahnenberg
Comment 3 2014-08-04 21:30:24 PDT
Created attachment 236003 [details] huffman benchmark
Mark Hahnenberg
Comment 4 2014-08-04 21:33:10 PDT
Created attachment 236004 [details] huffman benchmark
Mark Hahnenberg
Comment 5 2014-08-04 21:38:50 PDT
It looks like during the prediction injection phase we notice that the argument is a StringIdent, but the Phantom continues to assume that it's a number which causes us to exit constantly.
Mark Hahnenberg
Comment 6 2014-08-05 15:27:36 PDT
Filip Pizlo
Comment 7 2014-08-05 15:41:04 PDT
Comment on attachment 236052 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=236052&action=review Almost there > Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h:309 > + case ValueToNumber: { Can we call it ToNumber? > Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h:318 > + if (child && child.isInt32()) { > + setConstant(node, child); > + break; > + } > + if (child && child.isNumber()) { > + setConstant(node, jsDoubleNumber(child.asNumber())); > + break; > + } I feel like this should just be: if (child && child.isNumber()) { setConstant(node, child); break; } > Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp:362 > + node->child1()->mergeFlags(flags); I would mask off NodeBytecodeUsesAsOther, as in: node->child1()->mergeFlags(flags & ~NodeNytecodeUsesAsOther) > Source/JavaScriptCore/dfg/DFGClobberize.h:351 > + read(MiscFields); It reads world. > Source/JavaScriptCore/dfg/DFGFixupPhase.cpp:1153 > + case ValueToNumber: This needs to have the identity stuff. And probably some stuff to use BooleanToNumber. > Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp:479 > + changed |= setPrediction(SpecFullNumber); This needs to be more granular. If the input is already an int or already a number then you should preserve the original input's type. Literally you want something like: if (node->child1()->prediction() & SpecCell) changed |= setPrediction(SpecFullNumber); else { SpeculatedType type = node->child1()->prediction(); if (type & SpecOther) { type &= ~SpecOther; type |= SpecInt32 | SpecDoubleNaN; } if (type & SpecBoolean) { type &= ~SpecBoolean; type |= SpecInt32; } mergePredicstion(type); }
Mark Hahnenberg
Comment 8 2014-08-06 14:15:25 PDT
Mark Hahnenberg
Comment 9 2014-08-08 14:20:08 PDT
Filip Pizlo
Comment 10 2014-08-21 15:20:08 PDT
Comment on attachment 236304 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=236304&action=review R=me. It would be slightly better if this also included the FTL implementation of ToNumber. Also, a test would be cool. I'm fine with the FTL implementation being a separate patch. As a test, maybe you could just land your huffman thing, if you haven't already? Even better, land both huffman, and a microbenchmark for +s. > Source/JavaScriptCore/dfg/DFGFixupPhase.cpp:1283 > + void fixupToNumber(Node* node) > + { > + if (node->child1()->shouldSpeculateInt32()) { > + fixIntOrBooleanEdge(node->child1()); > + node->convertToIdentity(); > + return; > + } > + > + if (node->child1()->shouldSpeculateMachineInt()) { > + fixEdge<Int52RepUse>(node->child1()); > + node->convertToIdentity(); > + node->setResult(NodeResultInt52); > + return; > + } > + > + if (node->child1()->shouldSpeculateNumber()) { > + fixDoubleOrBooleanEdge(node->child1()); > + node->convertToIdentity(); > + node->setResult(NodeResultDouble); > + return; > + } > + } > + You only call this in one place so you might as well inline it. :-) fixupToPrimitive() had a method because we would call it in more than one place. Hopefully that's still the case, or else someone should probably inline it.
Note You need to log in before you can comment on or make changes to this bug.