OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 #include "hydrogen-store-elimination.h" | |
29 #include "hydrogen-instructions.h" | |
30 | |
31 namespace v8 { | |
32 namespace internal { | |
33 | |
34 #define TRACE(x) if (FLAG_trace_store_elimination) PrintF x | |
35 | |
36 // Performs a block-by-block local analysis for removable stores. | |
37 void HStoreEliminationPhase::Run() { | |
38 GVNFlagSet flags; // Use GVN flags as an approximation for some instructions. | |
39 flags.RemoveAll(); | |
40 | |
41 flags.Add(kDependsOnArrayElements); | |
42 flags.Add(kDependsOnArrayLengths); | |
43 flags.Add(kDependsOnStringLengths); | |
44 flags.Add(kDependsOnBackingStoreFields); | |
45 flags.Add(kDependsOnDoubleArrayElements); | |
46 flags.Add(kDependsOnDoubleFields); | |
47 flags.Add(kDependsOnElementsPointer); | |
48 flags.Add(kDependsOnInobjectFields); | |
49 flags.Add(kDependsOnExternalMemory); | |
50 | |
51 for (int i = 0; i < graph()->blocks()->length(); i++) { | |
52 unobserved_.Rewind(0); | |
53 HBasicBlock* block = graph()->blocks()->at(i); | |
54 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | |
55 HInstruction* instr = it.Current(); | |
56 | |
57 switch (instr->opcode()) { | |
58 case HValue::kStoreNamedField: | |
Hannes Payer (out of office)
2014/01/16 15:25:21
Can we also have that for keyed stores? Leave a TO
| |
59 // Remove any unobserved stores overwritten by this store. | |
60 ProcessStore(HStoreNamedField::cast(instr)); | |
61 break; | |
62 case HValue::kLoadNamedField: | |
63 // Observe any unobserved stores on this object + field. | |
64 ProcessLoad(HLoadNamedField::cast(instr)); | |
65 break; | |
66 default: | |
67 ProcessInstr(instr, flags); | |
68 break; | |
69 } | |
70 } | |
71 } | |
72 } | |
73 | |
74 | |
75 void HStoreEliminationPhase::ProcessStore(HStoreNamedField* store) { | |
76 HValue* object = store->object()->ActualValue(); | |
77 int i = 0; | |
78 while (i < unobserved_.length()) { | |
79 HStoreNamedField* prev = unobserved_.at(i); | |
80 if (aliasing_->MustAlias(object, prev->object()->ActualValue()) && | |
81 store->access().Equals(prev->access())) { | |
82 // This store is guaranteed to overwrite the previous store. | |
83 prev->DeleteAndReplaceWith(NULL); | |
84 TRACE(("++ Unobserved store S%d overwritten by S%d\n", | |
85 prev->id(), store->id())); | |
86 unobserved_.Remove(i); | |
87 } else { | |
88 // TODO(titzer): remove map word clearing from folded allocations. | |
89 i++; | |
90 } | |
91 } | |
92 // Only non-transitioning stores are removable. | |
93 if (!store->has_transition()) { | |
94 TRACE(("-- Might remove store S%d\n", store->id())); | |
95 unobserved_.Add(store, zone()); | |
96 } | |
97 } | |
98 | |
99 | |
100 void HStoreEliminationPhase::ProcessLoad(HLoadNamedField* load) { | |
101 HValue* object = load->object()->ActualValue(); | |
102 int i = 0; | |
103 while (i < unobserved_.length()) { | |
104 HStoreNamedField* prev = unobserved_.at(i); | |
105 if (aliasing_->MayAlias(object, prev->object()->ActualValue()) && | |
106 load->access().Equals(prev->access())) { | |
107 TRACE(("-- Observed store S%d by load L%d\n", prev->id(), load->id())); | |
108 unobserved_.Remove(i); | |
109 } else { | |
110 i++; | |
111 } | |
112 } | |
113 } | |
114 | |
115 | |
116 static bool CanDeoptimize(HInstruction* instr) { | |
Hannes Payer (out of office)
2014/01/16 15:25:21
This function looks pretty fragile, is there a mor
| |
117 // TODO(titzer): most binops can allocate? | |
118 switch (instr->opcode()) { | |
119 case HValue::kAccessArgumentsAt: | |
120 case HValue::kAdd: | |
121 case HValue::kApplyArguments: | |
122 case HValue::kArgumentsElements: | |
123 case HValue::kArgumentsLength: | |
124 case HValue::kArgumentsObject: | |
125 // TODO(titzer): non-tagged inputs case HValue::kBitwise: | |
Hannes Payer (out of office)
2014/01/16 15:25:21
that looks broken
| |
126 case HValue::kBoundsCheckBaseIndexInformation: | |
127 case HValue::kCapturedObject: | |
128 // TODO(titzer): non-tagged inputs case HValue::kChange: | |
129 case HValue::kClampToUint8: | |
130 // TODO(titzer): non-tagged inputs case HValue::kCompareGeneric: | |
131 case HValue::kConstant: | |
132 case HValue::kContext: | |
133 case HValue::kDateField: | |
134 case HValue::kDebugBreak: | |
135 case HValue::kDeclareGlobals: | |
136 case HValue::kDiv: | |
137 case HValue::kDummyUse: | |
138 case HValue::kElementsKind: | |
139 case HValue::kEnterInlined: | |
140 case HValue::kEnvironmentMarker: | |
141 case HValue::kForceRepresentation: | |
142 case HValue::kForInCacheArray: | |
143 case HValue::kForInPrepareMap: | |
144 case HValue::kFunctionLiteral: | |
145 case HValue::kGetCachedArrayIndex: | |
146 case HValue::kGlobalObject: | |
147 case HValue::kGlobalReceiver: | |
148 case HValue::kGoto: | |
149 case HValue::kInnerAllocatedObject: | |
150 case HValue::kInstanceOf: | |
151 case HValue::kInstanceOfKnownGlobal: | |
152 case HValue::kInvokeFunction: | |
153 case HValue::kLeaveInlined: | |
154 case HValue::kLoadContextSlot: | |
155 case HValue::kLoadExternalArrayPointer: | |
156 case HValue::kLoadFieldByIndex: | |
157 case HValue::kLoadFunctionPrototype: | |
158 case HValue::kLoadGlobalCell: | |
159 case HValue::kLoadGlobalGeneric: | |
160 case HValue::kLoadKeyed: | |
161 case HValue::kLoadKeyedGeneric: | |
162 case HValue::kLoadNamedField: | |
163 case HValue::kLoadNamedGeneric: | |
164 case HValue::kLoadRoot: | |
165 case HValue::kMapEnumLength: | |
166 case HValue::kMathFloorOfDiv: | |
167 case HValue::kMathMinMax: | |
168 case HValue::kMod: | |
169 case HValue::kMul: | |
170 case HValue::kOsrEntry: | |
171 case HValue::kOuterContext: | |
172 case HValue::kParameter: | |
173 case HValue::kPower: | |
174 case HValue::kPushArgument: | |
175 case HValue::kRor: | |
176 case HValue::kSar: | |
177 case HValue::kSeqStringGetChar: | |
178 case HValue::kSeqStringSetChar: | |
179 case HValue::kShl: | |
180 case HValue::kShr: | |
181 case HValue::kSimulate: | |
182 case HValue::kStackCheck: | |
183 case HValue::kStoreCodeEntry: | |
184 case HValue::kStoreContextSlot: | |
185 case HValue::kStoreGlobalCell: | |
186 case HValue::kStoreGlobalGeneric: | |
187 case HValue::kStoreKeyed: | |
188 case HValue::kStoreKeyedGeneric: | |
189 case HValue::kStoreNamedField: | |
190 case HValue::kStoreNamedGeneric: | |
191 case HValue::kStringAdd: | |
192 case HValue::kStringCharCodeAt: | |
193 case HValue::kStringCharFromCode: | |
194 case HValue::kSub: | |
195 case HValue::kThisFunction: | |
196 case HValue::kToFastProperties: | |
197 case HValue::kTransitionElementsKind: | |
198 case HValue::kTrapAllocationMemento: | |
199 case HValue::kTypeof: | |
200 case HValue::kUnaryMathOperation: | |
201 case HValue::kUseConst: | |
202 case HValue::kWrapReceiver: | |
203 return false; | |
204 default: | |
205 return true; | |
206 } | |
207 } | |
208 | |
209 | |
210 void HStoreEliminationPhase::ProcessInstr(HInstruction* instr, | |
211 GVNFlagSet flags) { | |
212 if (unobserved_.length() == 0) return; // Nothing to do. | |
213 if (CanDeoptimize(instr)) { | |
214 TRACE(("-- Observed stores at I%d (might deoptimize)\n", instr->id())); | |
215 unobserved_.Rewind(0); | |
216 return; | |
217 } | |
218 if (instr->CheckGVNFlag(kChangesNewSpacePromotion)) { | |
219 TRACE(("-- Observed stores at I%d (might GC)\n", instr->id())); | |
220 unobserved_.Rewind(0); | |
221 return; | |
222 } | |
223 if (instr->gvn_flags().ContainsAnyOf(flags)) { | |
224 TRACE(("-- Observed stores at I%d (GVN flags)\n", instr->id())); | |
225 unobserved_.Rewind(0); | |
226 return; | |
227 } | |
228 } | |
229 | |
230 } } // namespace v8::internal | |
OLD | NEW |