Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(169)

Side by Side Diff: src/compiler/memory-optimizer.cc

Issue 2602413002: [turbofan] Use graph assembler for memory optimizer. (Closed)
Patch Set: Refactor Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/memory-optimizer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/memory-optimizer.h" 5 #include "src/compiler/memory-optimizer.h"
6 6
7 #include "src/compiler/js-graph.h" 7 #include "src/compiler/js-graph.h"
8 #include "src/compiler/linkage.h" 8 #include "src/compiler/linkage.h"
9 #include "src/compiler/node-matchers.h" 9 #include "src/compiler/node-matchers.h"
10 #include "src/compiler/node-properties.h" 10 #include "src/compiler/node-properties.h"
11 #include "src/compiler/node.h" 11 #include "src/compiler/node.h"
12 #include "src/compiler/simplified-operator.h" 12 #include "src/compiler/simplified-operator.h"
13 13
14 namespace v8 { 14 namespace v8 {
15 namespace internal { 15 namespace internal {
16 namespace compiler { 16 namespace compiler {
17 17
18 MemoryOptimizer::MemoryOptimizer(JSGraph* jsgraph, Zone* zone) 18 MemoryOptimizer::MemoryOptimizer(JSGraph* jsgraph, Zone* zone)
19 : jsgraph_(jsgraph), 19 : jsgraph_(jsgraph),
20 empty_state_(AllocationState::Empty(zone)), 20 empty_state_(AllocationState::Empty(zone)),
21 pending_(zone), 21 pending_(zone),
22 tokens_(zone), 22 tokens_(zone),
23 zone_(zone) {} 23 zone_(zone),
24 graph_assembler_(jsgraph, nullptr, nullptr, zone) {}
24 25
25 void MemoryOptimizer::Optimize() { 26 void MemoryOptimizer::Optimize() {
26 EnqueueUses(graph()->start(), empty_state()); 27 EnqueueUses(graph()->start(), empty_state());
27 while (!tokens_.empty()) { 28 while (!tokens_.empty()) {
28 Token const token = tokens_.front(); 29 Token const token = tokens_.front();
29 tokens_.pop(); 30 tokens_.pop();
30 VisitNode(token.node, token.state); 31 VisitNode(token.node, token.state);
31 } 32 }
32 DCHECK(pending_.empty()); 33 DCHECK(pending_.empty());
33 DCHECK(tokens_.empty()); 34 DCHECK(tokens_.empty());
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 case IrOpcode::kProtectedStore: 97 case IrOpcode::kProtectedStore:
97 case IrOpcode::kRetain: 98 case IrOpcode::kRetain:
98 case IrOpcode::kUnsafePointerAdd: 99 case IrOpcode::kUnsafePointerAdd:
99 return VisitOtherEffect(node, state); 100 return VisitOtherEffect(node, state);
100 default: 101 default:
101 break; 102 break;
102 } 103 }
103 DCHECK_EQ(0, node->op()->EffectOutputCount()); 104 DCHECK_EQ(0, node->op()->EffectOutputCount());
104 } 105 }
105 106
107 #define __ gasm()->
108
106 void MemoryOptimizer::VisitAllocate(Node* node, AllocationState const* state) { 109 void MemoryOptimizer::VisitAllocate(Node* node, AllocationState const* state) {
107 DCHECK_EQ(IrOpcode::kAllocate, node->opcode()); 110 DCHECK_EQ(IrOpcode::kAllocate, node->opcode());
108 Node* value; 111 Node* value;
109 Node* size = node->InputAt(0); 112 Node* size = node->InputAt(0);
110 Node* effect = node->InputAt(1); 113 Node* effect = node->InputAt(1);
111 Node* control = node->InputAt(2); 114 Node* control = node->InputAt(2);
115
116 gasm()->Reset(effect, control);
117
112 PretenureFlag pretenure = PretenureFlagOf(node->op()); 118 PretenureFlag pretenure = PretenureFlagOf(node->op());
113 119
114 // Propagate tenuring from outer allocations to inner allocations, i.e. 120 // Propagate tenuring from outer allocations to inner allocations, i.e.
115 // when we allocate an object in old space and store a newly allocated 121 // when we allocate an object in old space and store a newly allocated
116 // child object into the pretenured object, then the newly allocated 122 // child object into the pretenured object, then the newly allocated
117 // child object also should get pretenured to old space. 123 // child object also should get pretenured to old space.
118 if (pretenure == TENURED) { 124 if (pretenure == TENURED) {
119 for (Edge const edge : node->use_edges()) { 125 for (Edge const edge : node->use_edges()) {
120 Node* const user = edge.from(); 126 Node* const user = edge.from();
121 if (user->opcode() == IrOpcode::kStoreField && edge.index() == 0) { 127 if (user->opcode() == IrOpcode::kStoreField && edge.index() == 0) {
(...skipping 14 matching lines...) Expand all
136 if (parent->opcode() == IrOpcode::kAllocate && 142 if (parent->opcode() == IrOpcode::kAllocate &&
137 PretenureFlagOf(parent->op()) == TENURED) { 143 PretenureFlagOf(parent->op()) == TENURED) {
138 pretenure = TENURED; 144 pretenure = TENURED;
139 break; 145 break;
140 } 146 }
141 } 147 }
142 } 148 }
143 } 149 }
144 150
145 // Determine the top/limit addresses. 151 // Determine the top/limit addresses.
146 Node* top_address = jsgraph()->ExternalConstant( 152 Node* top_address = __ ExternalConstant(
147 pretenure == NOT_TENURED 153 pretenure == NOT_TENURED
148 ? ExternalReference::new_space_allocation_top_address(isolate()) 154 ? ExternalReference::new_space_allocation_top_address(isolate())
149 : ExternalReference::old_space_allocation_top_address(isolate())); 155 : ExternalReference::old_space_allocation_top_address(isolate()));
150 Node* limit_address = jsgraph()->ExternalConstant( 156 Node* limit_address = __ ExternalConstant(
151 pretenure == NOT_TENURED 157 pretenure == NOT_TENURED
152 ? ExternalReference::new_space_allocation_limit_address(isolate()) 158 ? ExternalReference::new_space_allocation_limit_address(isolate())
153 : ExternalReference::old_space_allocation_limit_address(isolate())); 159 : ExternalReference::old_space_allocation_limit_address(isolate()));
154 160
155 // Check if we can fold this allocation into a previous allocation represented 161 // Check if we can fold this allocation into a previous allocation represented
156 // by the incoming {state}. 162 // by the incoming {state}.
157 Int32Matcher m(size); 163 Int32Matcher m(size);
158 if (m.HasValue() && m.Value() < kMaxRegularHeapObjectSize) { 164 if (m.HasValue() && m.Value() < kMaxRegularHeapObjectSize) {
159 int32_t const object_size = m.Value(); 165 int32_t const object_size = m.Value();
160 if (state->size() <= kMaxRegularHeapObjectSize - object_size && 166 if (state->size() <= kMaxRegularHeapObjectSize - object_size &&
161 state->group()->pretenure() == pretenure) { 167 state->group()->pretenure() == pretenure) {
162 // We can fold this Allocate {node} into the allocation {group} 168 // We can fold this Allocate {node} into the allocation {group}
163 // represented by the given {state}. Compute the upper bound for 169 // represented by the given {state}. Compute the upper bound for
164 // the new {state}. 170 // the new {state}.
165 int32_t const state_size = state->size() + object_size; 171 int32_t const state_size = state->size() + object_size;
166 172
167 // Update the reservation check to the actual maximum upper bound. 173 // Update the reservation check to the actual maximum upper bound.
168 AllocationGroup* const group = state->group(); 174 AllocationGroup* const group = state->group();
169 if (OpParameter<int32_t>(group->size()) < state_size) { 175 if (OpParameter<int32_t>(group->size()) < state_size) {
170 NodeProperties::ChangeOp(group->size(), 176 NodeProperties::ChangeOp(group->size(),
171 common()->Int32Constant(state_size)); 177 common()->Int32Constant(state_size));
172 } 178 }
173 179
174 // Update the allocation top with the new object allocation. 180 // Update the allocation top with the new object allocation.
175 // TODO(bmeurer): Defer writing back top as much as possible. 181 // TODO(bmeurer): Defer writing back top as much as possible.
176 Node* top = graph()->NewNode(machine()->IntAdd(), state->top(), 182 Node* top = __ IntAdd(state->top(), __ IntPtrConstant(object_size));
177 jsgraph()->IntPtrConstant(object_size)); 183 __ Store(StoreRepresentation(MachineType::PointerRepresentation(),
178 effect = graph()->NewNode( 184 kNoWriteBarrier),
179 machine()->Store(StoreRepresentation( 185 top_address, __ IntPtrConstant(0), top);
180 MachineType::PointerRepresentation(), kNoWriteBarrier)),
181 top_address, jsgraph()->IntPtrConstant(0), top, effect, control);
182 186
183 // Compute the effective inner allocated address. 187 // Compute the effective inner allocated address.
184 value = graph()->NewNode( 188 value = __ BitcastWordToTagged(
185 machine()->BitcastWordToTagged(), 189 __ IntAdd(state->top(), __ IntPtrConstant(kHeapObjectTag)));
186 graph()->NewNode(machine()->IntAdd(), state->top(),
187 jsgraph()->IntPtrConstant(kHeapObjectTag)));
188 190
189 // Extend the allocation {group}. 191 // Extend the allocation {group}.
190 group->Add(value); 192 group->Add(value);
191 state = AllocationState::Open(group, state_size, top, zone()); 193 state = AllocationState::Open(group, state_size, top, zone());
192 } else { 194 } else {
195 auto call_runtime = __ MakeDeferredLabel<1>();
196 auto done = __ MakeLabel<2>(MachineType::PointerRepresentation());
197
193 // Setup a mutable reservation size node; will be patched as we fold 198 // Setup a mutable reservation size node; will be patched as we fold
194 // additional allocations into this new group. 199 // additional allocations into this new group.
195 Node* size = graph()->NewNode(common()->Int32Constant(object_size)); 200 Node* size = __ UniqueInt32Constant(object_size);
196 201
197 // Load allocation top and limit. 202 // Load allocation top and limit.
198 Node* top = effect = 203 Node* top =
199 graph()->NewNode(machine()->Load(MachineType::Pointer()), top_address, 204 __ Load(MachineType::Pointer(), top_address, __ IntPtrConstant(0));
200 jsgraph()->IntPtrConstant(0), effect, control); 205 Node* limit =
201 Node* limit = effect = graph()->NewNode( 206 __ Load(MachineType::Pointer(), limit_address, __ IntPtrConstant(0));
202 machine()->Load(MachineType::Pointer()), limit_address,
203 jsgraph()->IntPtrConstant(0), effect, control);
204 207
205 // Check if we need to collect garbage before we can start bump pointer 208 // Check if we need to collect garbage before we can start bump pointer
206 // allocation (always done for folded allocations). 209 // allocation (always done for folded allocations).
207 Node* check = graph()->NewNode( 210 Node* check = __ UintLessThan(
208 machine()->UintLessThan(), 211 __ IntAdd(top,
209 graph()->NewNode( 212 machine()->Is64() ? __ ChangeInt32ToInt64(size) : size),
210 machine()->IntAdd(), top,
211 machine()->Is64()
212 ? graph()->NewNode(machine()->ChangeInt32ToInt64(), size)
213 : size),
214 limit); 213 limit);
215 Node* branch =
216 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
217 214
218 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 215 __ GotoUnless(check, &call_runtime);
219 Node* etrue = effect; 216 __ Goto(&done, top);
220 Node* vtrue = top;
221 217
222 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 218 __ Bind(&call_runtime);
223 Node* efalse = effect;
224 Node* vfalse;
225 { 219 {
226 Node* target = pretenure == NOT_TENURED 220 Node* target =
227 ? jsgraph()->AllocateInNewSpaceStubConstant() 221 pretenure == NOT_TENURED ? __ AllocateInNewSpaceStubConstant()
228 : jsgraph()->AllocateInOldSpaceStubConstant(); 222 : __
223 AllocateInOldSpaceStubConstant();
229 if (!allocate_operator_.is_set()) { 224 if (!allocate_operator_.is_set()) {
230 CallDescriptor* descriptor = 225 CallDescriptor* descriptor =
231 Linkage::GetAllocateCallDescriptor(graph()->zone()); 226 Linkage::GetAllocateCallDescriptor(graph()->zone());
232 allocate_operator_.set(common()->Call(descriptor)); 227 allocate_operator_.set(common()->Call(descriptor));
233 } 228 }
234 vfalse = efalse = graph()->NewNode(allocate_operator_.get(), target, 229 Node* vfalse = __ Call(allocate_operator_.get(), target, size);
235 size, efalse, if_false); 230 vfalse = __ IntSub(vfalse, __ IntPtrConstant(kHeapObjectTag));
236 vfalse = graph()->NewNode(machine()->IntSub(), vfalse, 231 __ Goto(&done, vfalse);
237 jsgraph()->IntPtrConstant(kHeapObjectTag));
238 } 232 }
239 233
240 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 234 __ Bind(&done);
241 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
242 value = graph()->NewNode(
243 common()->Phi(MachineType::PointerRepresentation(), 2), vtrue, vfalse,
244 control);
245 235
246 // Compute the new top and write it back. 236 // Compute the new top and write it back.
247 top = graph()->NewNode(machine()->IntAdd(), value, 237 top = __ IntAdd(done.PhiAt(0), __ IntPtrConstant(object_size));
248 jsgraph()->IntPtrConstant(object_size)); 238 __ Store(StoreRepresentation(MachineType::PointerRepresentation(),
249 effect = graph()->NewNode( 239 kNoWriteBarrier),
250 machine()->Store(StoreRepresentation( 240 top_address, __ IntPtrConstant(0), top);
251 MachineType::PointerRepresentation(), kNoWriteBarrier)),
252 top_address, jsgraph()->IntPtrConstant(0), top, effect, control);
253 241
254 // Compute the initial object address. 242 // Compute the initial object address.
255 value = graph()->NewNode( 243 value = __ BitcastWordToTagged(
256 machine()->BitcastWordToTagged(), 244 __ IntAdd(done.PhiAt(0), __ IntPtrConstant(kHeapObjectTag)));
257 graph()->NewNode(machine()->IntAdd(), value,
258 jsgraph()->IntPtrConstant(kHeapObjectTag)));
259 245
260 // Start a new allocation group. 246 // Start a new allocation group.
261 AllocationGroup* group = 247 AllocationGroup* group =
262 new (zone()) AllocationGroup(value, pretenure, size, zone()); 248 new (zone()) AllocationGroup(value, pretenure, size, zone());
263 state = AllocationState::Open(group, object_size, top, zone()); 249 state = AllocationState::Open(group, object_size, top, zone());
264 } 250 }
265 } else { 251 } else {
252 auto call_runtime = __ MakeDeferredLabel<1>();
253 auto done = __ MakeLabel<2>(MachineRepresentation::kTaggedPointer);
254
266 // Load allocation top and limit. 255 // Load allocation top and limit.
267 Node* top = effect = 256 Node* top =
268 graph()->NewNode(machine()->Load(MachineType::Pointer()), top_address, 257 __ Load(MachineType::Pointer(), top_address, __ IntPtrConstant(0));
269 jsgraph()->IntPtrConstant(0), effect, control); 258 Node* limit =
270 Node* limit = effect = 259 __ Load(MachineType::Pointer(), limit_address, __ IntPtrConstant(0));
271 graph()->NewNode(machine()->Load(MachineType::Pointer()), limit_address,
272 jsgraph()->IntPtrConstant(0), effect, control);
273 260
274 // Compute the new top. 261 // Compute the new top.
275 Node* new_top = graph()->NewNode( 262 Node* new_top =
276 machine()->IntAdd(), top, 263 __ IntAdd(top, machine()->Is64() ? __ ChangeInt32ToInt64(size) : size);
277 machine()->Is64()
278 ? graph()->NewNode(machine()->ChangeInt32ToInt64(), size)
279 : size);
280 264
281 // Check if we can do bump pointer allocation here. 265 // Check if we can do bump pointer allocation here.
282 Node* check = graph()->NewNode(machine()->UintLessThan(), new_top, limit); 266 Node* check = __ UintLessThan(new_top, limit);
283 Node* branch = 267 __ GotoUnless(check, &call_runtime);
284 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 268 __ Store(StoreRepresentation(MachineType::PointerRepresentation(),
269 kNoWriteBarrier),
270 top_address, __ IntPtrConstant(0), new_top);
271 __ Goto(&done, __ BitcastWordToTagged(
272 __ IntAdd(top, __ IntPtrConstant(kHeapObjectTag))));
285 273
286 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 274 __ Bind(&call_runtime);
287 Node* etrue = effect; 275 Node* target =
288 Node* vtrue; 276 pretenure == NOT_TENURED ? __ AllocateInNewSpaceStubConstant()
289 { 277 : __
290 etrue = graph()->NewNode( 278 AllocateInOldSpaceStubConstant();
291 machine()->Store(StoreRepresentation( 279 if (!allocate_operator_.is_set()) {
292 MachineType::PointerRepresentation(), kNoWriteBarrier)), 280 CallDescriptor* descriptor =
293 top_address, jsgraph()->IntPtrConstant(0), new_top, etrue, if_true); 281 Linkage::GetAllocateCallDescriptor(graph()->zone());
294 vtrue = graph()->NewNode( 282 allocate_operator_.set(common()->Call(descriptor));
295 machine()->BitcastWordToTagged(),
296 graph()->NewNode(machine()->IntAdd(), top,
297 jsgraph()->IntPtrConstant(kHeapObjectTag)));
298 } 283 }
284 __ Goto(&done, __ Call(allocate_operator_.get(), target, size));
299 285
300 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 286 __ Bind(&done);
301 Node* efalse = effect; 287 value = done.PhiAt(0);
302 Node* vfalse;
303 {
304 Node* target = pretenure == NOT_TENURED
305 ? jsgraph()->AllocateInNewSpaceStubConstant()
306 : jsgraph()->AllocateInOldSpaceStubConstant();
307 if (!allocate_operator_.is_set()) {
308 CallDescriptor* descriptor =
309 Linkage::GetAllocateCallDescriptor(graph()->zone());
310 allocate_operator_.set(common()->Call(descriptor));
311 }
312 vfalse = efalse = graph()->NewNode(allocate_operator_.get(), target, size,
313 efalse, if_false);
314 }
315
316 control = graph()->NewNode(common()->Merge(2), if_true, if_false);
317 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
318 value = graph()->NewNode(
319 common()->Phi(MachineRepresentation::kTaggedPointer, 2), vtrue, vfalse,
320 control);
321 288
322 // Create an unfoldable allocation group. 289 // Create an unfoldable allocation group.
323 AllocationGroup* group = 290 AllocationGroup* group =
324 new (zone()) AllocationGroup(value, pretenure, zone()); 291 new (zone()) AllocationGroup(value, pretenure, zone());
325 state = AllocationState::Closed(group, zone()); 292 state = AllocationState::Closed(group, zone());
326 } 293 }
327 294
295 effect = __ ExtractCurrentEffect();
296 control = __ ExtractCurrentControl();
297 USE(control); // Floating control, dropped on the floor.
298
328 // Replace all effect uses of {node} with the {effect}, enqueue the 299 // Replace all effect uses of {node} with the {effect}, enqueue the
329 // effect uses for further processing, and replace all value uses of 300 // effect uses for further processing, and replace all value uses of
330 // {node} with the {value}. 301 // {node} with the {value}.
331 for (Edge edge : node->use_edges()) { 302 for (Edge edge : node->use_edges()) {
332 if (NodeProperties::IsEffectEdge(edge)) { 303 if (NodeProperties::IsEffectEdge(edge)) {
333 EnqueueUse(edge.from(), edge.index(), state); 304 EnqueueUse(edge.from(), edge.index(), state);
334 edge.UpdateTo(effect); 305 edge.UpdateTo(effect);
335 } else { 306 } else {
336 DCHECK(NodeProperties::IsValueEdge(edge)); 307 DCHECK(NodeProperties::IsValueEdge(edge));
337 edge.UpdateTo(value); 308 edge.UpdateTo(value);
338 } 309 }
339 } 310 }
340 311
341 // Kill the {node} to make sure we don't leave dangling dead uses. 312 // Kill the {node} to make sure we don't leave dangling dead uses.
342 node->Kill(); 313 node->Kill();
343 } 314 }
344 315
316 #undef __
317
345 void MemoryOptimizer::VisitCall(Node* node, AllocationState const* state) { 318 void MemoryOptimizer::VisitCall(Node* node, AllocationState const* state) {
346 DCHECK_EQ(IrOpcode::kCall, node->opcode()); 319 DCHECK_EQ(IrOpcode::kCall, node->opcode());
347 // If the call can allocate, we start with a fresh state. 320 // If the call can allocate, we start with a fresh state.
348 if (!(CallDescriptorOf(node->op())->flags() & CallDescriptor::kNoAllocate)) { 321 if (!(CallDescriptorOf(node->op())->flags() & CallDescriptor::kNoAllocate)) {
349 state = empty_state(); 322 state = empty_state();
350 } 323 }
351 EnqueueUses(node, state); 324 EnqueueUses(node, state);
352 } 325 }
353 326
354 void MemoryOptimizer::VisitLoadElement(Node* node, 327 void MemoryOptimizer::VisitLoadElement(Node* node,
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 return jsgraph()->common(); 501 return jsgraph()->common();
529 } 502 }
530 503
531 MachineOperatorBuilder* MemoryOptimizer::machine() const { 504 MachineOperatorBuilder* MemoryOptimizer::machine() const {
532 return jsgraph()->machine(); 505 return jsgraph()->machine();
533 } 506 }
534 507
535 } // namespace compiler 508 } // namespace compiler
536 } // namespace internal 509 } // namespace internal
537 } // namespace v8 510 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/memory-optimizer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698