Source/JavaScriptCore/ChangeLog

 12013-02-25 Filip Pizlo <fpizlo@apple.com>
 2
 3 The DFG backend's and OSR's decision to unbox a variable should be based on whether it's used in a typed context
 4 https://bugs.webkit.org/show_bug.cgi?id=110433
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 This introduces the equivalent of a liveness analysis, except for type checking.
 9 A variable is said to be "profitable for unboxing" (i.e. live at a type check)
 10 if there exists a type check on a GetLocal of that variable, and the type check
 11 is consistent with the variable's prediction. Variables that are not profitable
 12 for unboxing aren't unboxed. Previously they would have been.
 13
 14 This is a slight speed-up on some things but mostly neutral.
 15
 16 * dfg/DFGArgumentPosition.h:
 17 (JSC::DFG::ArgumentPosition::ArgumentPosition):
 18 (JSC::DFG::ArgumentPosition::mergeShouldNeverUnbox):
 19 (JSC::DFG::ArgumentPosition::mergeArgumentPredictionAwareness):
 20 (JSC::DFG::ArgumentPosition::mergeArgumentUnboxingAwareness):
 21 (ArgumentPosition):
 22 (JSC::DFG::ArgumentPosition::isProfitableToUnbox):
 23 (JSC::DFG::ArgumentPosition::shouldUseDoubleFormat):
 24 * dfg/DFGCommon.h:
 25 (JSC::DFG::setAndCheck):
 26 (DFG):
 27 * dfg/DFGFixupPhase.cpp:
 28 (JSC::DFG::FixupPhase::run):
 29 (JSC::DFG::FixupPhase::fixupNode):
 30 (JSC::DFG::FixupPhase::fixupSetLocalsInBlock):
 31 (FixupPhase):
 32 (JSC::DFG::FixupPhase::alwaysUnboxSimplePrimitives):
 33 (JSC::DFG::FixupPhase::setUseKindAndUnboxIfProfitable):
 34 * dfg/DFGPredictionPropagationPhase.cpp:
 35 (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
 36 * dfg/DFGSpeculativeJIT.cpp:
 37 (JSC::DFG::SpeculativeJIT::checkArgumentTypes):
 38 * dfg/DFGVariableAccessData.h:
 39 (JSC::DFG::VariableAccessData::VariableAccessData):
 40 (JSC::DFG::VariableAccessData::mergeIsCaptured):
 41 (JSC::DFG::VariableAccessData::mergeIsProfitableToUnbox):
 42 (VariableAccessData):
 43 (JSC::DFG::VariableAccessData::isProfitableToUnbox):
 44 (JSC::DFG::VariableAccessData::shouldUnboxIfPossible):
 45 (JSC::DFG::VariableAccessData::mergeStructureCheckHoistingFailed):
 46 (JSC::DFG::VariableAccessData::mergeIsArgumentsAlias):
 47 (JSC::DFG::VariableAccessData::shouldUseDoubleFormat):
 48 (JSC::DFG::VariableAccessData::mergeFlags):
 49
1502013-02-26 Oliver Hunt <oliver@apple.com>
251
352 Web Inspector: REGRESSION: [JSC] SourceProvider reuses IDs
144122

Source/JavaScriptCore/dfg/DFGArgumentPosition.h

11/*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
 2 * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
33 *
44 * Redistribution and use in source and binary forms, with or without
55 * modification, are permitted provided that the following conditions

@@public:
3737 ArgumentPosition()
3838 : m_prediction(SpecNone)
3939 , m_doubleFormatState(EmptyDoubleFormatState)
 40 , m_isProfitableToUnbox(false)
4041 , m_shouldNeverUnbox(false)
4142 {
4243 }

@@public:
4849
4950 bool mergeShouldNeverUnbox(bool shouldNeverUnbox)
5051 {
51  bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox;
52  if (newShouldNeverUnbox == m_shouldNeverUnbox)
53  return false;
54  m_shouldNeverUnbox = newShouldNeverUnbox;
55  return true;
 52 return setAndCheck(m_shouldNeverUnbox, m_shouldNeverUnbox | shouldNeverUnbox);
5653 }
5754
58  bool mergeArgumentAwareness()
 55 bool mergeArgumentPredictionAwareness()
5956 {
6057 bool changed = false;
6158 for (unsigned i = 0; i < m_variables.size(); ++i) {

@@public:
7471 return changed;
7572 }
7673
 74 bool mergeArgumentUnboxingAwareness()
 75 {
 76 bool changed = false;
 77 for (unsigned i = 0; i < m_variables.size(); ++i)
 78 changed |= setAndCheck(m_isProfitableToUnbox, m_isProfitableToUnbox | m_variables[i]->isProfitableToUnbox());
 79 if (!changed)
 80 return false;
 81 changed = false;
 82 for (unsigned i = 0; i < m_variables.size(); ++i)
 83 changed |= m_variables[i]->mergeIsProfitableToUnbox(m_isProfitableToUnbox);
 84 return changed;
 85 }
 86
 87 bool shouldUnboxIfPossible() const { return m_isProfitableToUnbox && !m_shouldNeverUnbox; }
 88
7789 SpeculatedType prediction() const { return m_prediction; }
7890 DoubleFormatState doubleFormatState() const { return m_doubleFormatState; }
7991 bool shouldUseDoubleFormat() const
8092 {
81  return doubleFormatState() == UsingDoubleFormat;
 93 return doubleFormatState() == UsingDoubleFormat && shouldUnboxIfPossible();
8294 }
8395
8496private:
8597 SpeculatedType m_prediction;
8698 DoubleFormatState m_doubleFormatState;
 99 bool m_isProfitableToUnbox;
87100 bool m_shouldNeverUnbox;
88101
89102 Vector<VariableAccessData*, 2> m_variables;
144122

Source/JavaScriptCore/dfg/DFGCommon.h

@@enum OperandSpeculationMode { AutomaticO
221221
222222enum SpeculationDirection { ForwardSpeculation, BackwardSpeculation };
223223
 224template<typename T, typename U>
 225bool setAndCheck(T& left, U right)
 226{
 227 if (left == right)
 228 return false;
 229 left = right;
 230 return true;
 231}
 232
224233} } // namespace JSC::DFG
225234
226235namespace WTF {
144122

Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

3131#include "DFGGraph.h"
3232#include "DFGInsertionSet.h"
3333#include "DFGPhase.h"
 34#include "DFGVariableAccessDataDump.h"
3435#include "Operations.h"
3536
3637namespace JSC { namespace DFG {

@@public:
4849 ASSERT(m_graph.m_fixpointState == BeforeFixpoint);
4950 ASSERT(m_graph.m_form == ThreadedCPS);
5051
 52 m_profitabilityChanged = false;
5153 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
5254 fixupBlock(m_graph.m_blocks[blockIndex].get());
 55
 56 while (m_profitabilityChanged) {
 57 m_profitabilityChanged = false;
 58
 59 for (unsigned i = m_graph.m_argumentPositions.size(); i--;)
 60 m_graph.m_argumentPositions[i].mergeArgumentUnboxingAwareness();
 61
 62 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
 63 fixupSetLocalsInBlock(m_graph.m_blocks[blockIndex].get());
 64 }
 65
5366 return true;
5467 }
5568

@@private:
8093
8194 switch (op) {
8295 case SetLocal: {
83  VariableAccessData* variable = node->variableAccessData();
84 
85  if (!variable->shouldUnboxIfPossible())
86  break;
87 
88  if (variable->shouldUseDoubleFormat()) {
89  fixDoubleEdge<NumberUse>(node->child1(), ForwardSpeculation);
90  break;
91  }
92 
93  SpeculatedType predictedType = variable->argumentAwarePrediction();
94  if (isInt32Speculation(predictedType))
95  setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
96  else if (isCellSpeculation(predictedType))
97  setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
98  else if (isBooleanSpeculation(predictedType))
99  setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
 96 // This gets handled by fixupSetLocalsInBlock().
10097 break;
10198 }
10299

@@private:
807804#endif
808805 }
809806
 807 void fixupSetLocalsInBlock(BasicBlock* block)
 808 {
 809 if (!block)
 810 return;
 811 ASSERT(block->isReachable);
 812 m_block = block;
 813 for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
 814 Node* node = m_currentNode = block->at(m_indexInBlock);
 815 if (node->op() != SetLocal)
 816 continue;
 817 if (!node->shouldGenerate())
 818 continue;
 819
 820 VariableAccessData* variable = node->variableAccessData();
 821
 822 if (!variable->shouldUnboxIfPossible())
 823 continue;
 824
 825 if (variable->shouldUseDoubleFormat()) {
 826 fixDoubleEdge<NumberUse>(node->child1(), ForwardSpeculation);
 827 continue;
 828 }
 829
 830 SpeculatedType predictedType = variable->argumentAwarePrediction();
 831 if (isInt32Speculation(predictedType))
 832 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
 833 else if (isCellSpeculation(predictedType))
 834 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
 835 else if (isBooleanSpeculation(predictedType))
 836 setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
 837 }
 838 m_insertionSet.execute(block);
 839 }
 840
810841 Node* checkArray(ArrayMode arrayMode, CodeOrigin codeOrigin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage, bool shouldGenerate = true)
811842 {
812843 ASSERT(arrayMode.isSpecific());

@@private:
895926 } }
896927 }
897928
 929 bool alwaysUnboxSimplePrimitives()
 930 {
 931#if USE(JSVALUE64)
 932 return false;
 933#else
 934 // Any boolean, int, or cell value is profitable to unbox on 32-bit because it
 935 // reduces traffic.
 936 return true;
 937#endif
 938 }
 939
898940 // Set the use kind of the edge. In the future (https://bugs.webkit.org/show_bug.cgi?id=110433),
899941 // this can be used to notify the GetLocal that the variable is profitable to unbox.
900942 template<UseKind useKind>
901943 void setUseKindAndUnboxIfProfitable(Edge& edge)
902944 {
 945 if (edge->op() == GetLocal) {
 946 VariableAccessData* variable = edge->variableAccessData();
 947 switch (useKind) {
 948 case Int32Use:
 949 if (alwaysUnboxSimplePrimitives()
 950 || isInt32Speculation(variable->prediction()))
 951 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
 952 break;
 953 case NumberUse:
 954 case RealNumberUse:
 955 if (variable->doubleFormatState() == UsingDoubleFormat)
 956 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
 957 break;
 958 case BooleanUse:
 959 if (alwaysUnboxSimplePrimitives()
 960 || isBooleanSpeculation(variable->prediction()))
 961 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
 962 break;
 963 case CellUse:
 964 case ObjectUse:
 965 case StringUse:
 966 if (alwaysUnboxSimplePrimitives()
 967 || isCellSpeculation(variable->prediction()))
 968 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
 969 break;
 970 default:
 971 break;
 972 }
 973 }
 974
903975 edge.setUseKind(useKind);
904976 }
905977

@@private:
10011073 unsigned m_indexInBlock;
10021074 Node* m_currentNode;
10031075 InsertionSet m_insertionSet;
 1076 bool m_profitabilityChanged;
10041077};
10051078
10061079bool performFixup(Graph& graph)
144122

Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

@@private:
10251025 m_changed |= variableAccessData->tallyVotesForShouldUseDoubleFormat();
10261026 }
10271027 for (unsigned i = 0; i < m_graph.m_argumentPositions.size(); ++i)
1028  m_changed |= m_graph.m_argumentPositions[i].mergeArgumentAwareness();
 1028 m_changed |= m_graph.m_argumentPositions[i].mergeArgumentPredictionAwareness();
10291029 for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
10301030 VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
10311031 if (!variableAccessData->isRoot())
144122

Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

@@void SpeculativeJIT::compile(BasicBlock&
16461646 valueSource = ValueSource(SourceIsDead);
16471647 else if (node->variableAccessData()->isArgumentsAlias())
16481648 valueSource = ValueSource(ArgumentsSource);
1649  else if (!node->variableAccessData()->shouldUnboxIfPossible())
1650  valueSource = ValueSource(ValueInJSStack);
16511649 else if (!node->refCount())
16521650 valueSource = ValueSource(SourceIsDead);
 1651 else if (!node->variableAccessData()->shouldUnboxIfPossible())
 1652 valueSource = ValueSource(ValueInJSStack);
16531653 else if (node->variableAccessData()->shouldUseDoubleFormat())
16541654 valueSource = ValueSource(DoubleInJSStack);
16551655 else

@@void SpeculativeJIT::compile(BasicBlock&
17121712 ArgumentPosition& argumentPosition =
17131713 m_jit.graph().m_argumentPositions[argumentPositionStart + i];
17141714 ValueSource valueSource;
1715  if (argumentPosition.shouldUseDoubleFormat())
 1715 if (!argumentPosition.shouldUnboxIfPossible())
 1716 valueSource = ValueSource(ValueInJSStack);
 1717 else if (argumentPosition.shouldUseDoubleFormat())
17161718 valueSource = ValueSource(DoubleInJSStack);
17171719 else if (isInt32Speculation(argumentPosition.prediction()))
17181720 valueSource = ValueSource(Int32InJSStack);

@@void SpeculativeJIT::checkArgumentTypes(
18391841 }
18401842
18411843 VariableAccessData* variableAccessData = node->variableAccessData();
 1844 if (!variableAccessData->isProfitableToUnbox())
 1845 continue;
 1846
18421847 VirtualRegister virtualRegister = variableAccessData->local();
18431848 SpeculatedType predictedType = variableAccessData->prediction();
18441849
144122

Source/JavaScriptCore/dfg/DFGVariableAccessData.h

11/*
2  * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
 2 * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
33 *
44 * Redistribution and use in source and binary forms, with or without
55 * modification, are permitted provided that the following conditions

@@public:
5050 , m_shouldNeverUnbox(false)
5151 , m_isArgumentsAlias(false)
5252 , m_structureCheckHoistingFailed(false)
 53 , m_isProfitableToUnbox(false)
5354 , m_doubleFormatState(EmptyDoubleFormatState)
5455 {
5556 clearVotes();

@@public:
6465 , m_shouldNeverUnbox(isCaptured)
6566 , m_isArgumentsAlias(false)
6667 , m_structureCheckHoistingFailed(false)
 68 , m_isProfitableToUnbox(false)
6769 , m_doubleFormatState(EmptyDoubleFormatState)
6870 {
6971 clearVotes();

@@public:
8284
8385 bool mergeIsCaptured(bool isCaptured)
8486 {
85  m_shouldNeverUnbox |= isCaptured;
86  bool newIsCaptured = m_isCaptured | isCaptured;
87  if (newIsCaptured == m_isCaptured)
88  return false;
89  m_isCaptured = newIsCaptured;
90  return true;
 87 return setAndCheck(m_shouldNeverUnbox, m_shouldNeverUnbox | isCaptured)
 88 | setAndCheck(m_isCaptured, m_isCaptured | isCaptured);
9189 }
9290
9391 bool isCaptured()

@@public:
9593 return m_isCaptured;
9694 }
9795
 96 bool mergeIsProfitableToUnbox(bool isProfitableToUnbox)
 97 {
 98 return setAndCheck(m_isProfitableToUnbox, m_isProfitableToUnbox | isProfitableToUnbox);
 99 }
 100
 101 bool isProfitableToUnbox()
 102 {
 103 return m_isProfitableToUnbox;
 104 }
 105
98106 bool mergeShouldNeverUnbox(bool shouldNeverUnbox)
99107 {
100108 bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox;

@@public:
118126 // returns false, since this incorporates heuristics of profitability.
119127 bool shouldUnboxIfPossible()
120128 {
121  return !shouldNeverUnbox();
 129 return !shouldNeverUnbox() && isProfitableToUnbox();
122130 }
123 
 131
124132 bool mergeStructureCheckHoistingFailed(bool failed)
125133 {
126  bool newFailed = m_structureCheckHoistingFailed | failed;
127  if (newFailed == m_structureCheckHoistingFailed)
128  return false;
129  m_structureCheckHoistingFailed = newFailed;
130  return true;
 134 return setAndCheck(m_structureCheckHoistingFailed, m_structureCheckHoistingFailed | failed);
131135 }
132136
133137 bool structureCheckHoistingFailed()

@@public:
137141
138142 bool mergeIsArgumentsAlias(bool isArgumentsAlias)
139143 {
140  bool newIsArgumentsAlias = m_isArgumentsAlias | isArgumentsAlias;
141  if (newIsArgumentsAlias == m_isArgumentsAlias)
142  return false;
143  m_isArgumentsAlias = newIsArgumentsAlias;
144  return true;
 144 return setAndCheck(m_isArgumentsAlias, m_isArgumentsAlias | isArgumentsAlias);
145145 }
146146
147147 bool isArgumentsAlias()

@@public:
239239 bool shouldUseDoubleFormat()
240240 {
241241 ASSERT(isRoot());
242  bool result = m_doubleFormatState == UsingDoubleFormat;
243  ASSERT(!(result && shouldNeverUnbox()));
244  ASSERT(!(result && isCaptured()));
245  return result;
 242 bool doubleState = m_doubleFormatState == UsingDoubleFormat;
 243 ASSERT(!(doubleState && shouldNeverUnbox()));
 244 ASSERT(!(doubleState && isCaptured()));
 245 return doubleState && isProfitableToUnbox();
246246 }
247247
248248 bool tallyVotesForShouldUseDoubleFormat()

@@public:
287287
288288 bool mergeFlags(NodeFlags newFlags)
289289 {
290  newFlags |= m_flags;
291  if (newFlags == m_flags)
292  return false;
293  m_flags = newFlags;
294  return true;
 290 return setAndCheck(m_flags, m_flags | newFlags);
295291 }
296292
297293private:

@@private:
304300 SpeculatedType m_prediction;
305301 SpeculatedType m_argumentAwarePrediction;
306302 NodeFlags m_flags;
307 
 303
308304 bool m_isCaptured;
309305 bool m_shouldNeverUnbox;
310306 bool m_isArgumentsAlias;
311307 bool m_structureCheckHoistingFailed;
 308 bool m_isProfitableToUnbox;
312309
313310 float m_votes[2]; // Used primarily for double voting but may be reused for other purposes.
314311 DoubleFormatState m_doubleFormatState;
144122