OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/instruction-selector.h" | 5 #include "src/compiler/instruction-selector.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "src/base/adapters.h" | 9 #include "src/base/adapters.h" |
10 #include "src/compiler/instruction-selector-impl.h" | 10 #include "src/compiler/instruction-selector-impl.h" |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 rep = RepresentationOf(rep); | 252 rep = RepresentationOf(rep); |
253 sequence()->MarkAsRepresentation(rep, GetVirtualRegister(node)); | 253 sequence()->MarkAsRepresentation(rep, GetVirtualRegister(node)); |
254 } | 254 } |
255 | 255 |
256 | 256 |
257 namespace { | 257 namespace { |
258 | 258 |
259 enum class FrameStateInputKind { kAny, kStackSlot }; | 259 enum class FrameStateInputKind { kAny, kStackSlot }; |
260 | 260 |
261 | 261 |
262 InstructionOperand OperandForDeopt(OperandGenerator* g, Node* input, | 262 InstructionOperand OperandForDeopt(OperandGenerator* g, Node* node, |
263 FrameStateInputKind kind) { | 263 FrameStateInputKind kind) { |
264 switch (input->opcode()) { | 264 switch (node->opcode()) { |
265 case IrOpcode::kInt32Constant: | 265 case IrOpcode::kInt32Constant: |
266 case IrOpcode::kNumberConstant: | 266 case IrOpcode::kNumberConstant: |
267 case IrOpcode::kFloat32Constant: | 267 case IrOpcode::kFloat32Constant: |
268 case IrOpcode::kFloat64Constant: | 268 case IrOpcode::kFloat64Constant: |
269 case IrOpcode::kHeapConstant: | 269 case IrOpcode::kHeapConstant: |
270 return g->UseImmediate(input); | 270 return g->UseImmediate(node); |
271 default: | 271 default: |
272 switch (kind) { | 272 switch (kind) { |
273 case FrameStateInputKind::kStackSlot: | 273 case FrameStateInputKind::kStackSlot: |
274 return g->UseUniqueSlot(input); | 274 return g->UseUniqueSlot(node); |
275 case FrameStateInputKind::kAny: | 275 case FrameStateInputKind::kAny: |
276 return g->UseAny(input); | 276 return g->UseAny(node); |
277 } | 277 } |
278 UNREACHABLE(); | 278 } |
279 return InstructionOperand(); | 279 UNREACHABLE(); |
| 280 return InstructionOperand(); |
| 281 } |
| 282 |
| 283 |
| 284 class StateObjectCache { |
| 285 public: |
| 286 explicit StateObjectCache(Zone* zone) : objects_(zone) {} |
| 287 static const size_t kNotCached = SIZE_MAX; |
| 288 |
| 289 size_t GetObjectId(Node* node) { |
| 290 for (size_t i = 0; i < objects_.size(); ++i) { |
| 291 if (objects_[i] == node) { |
| 292 return i; |
| 293 } |
| 294 } |
| 295 return kNotCached; |
| 296 } |
| 297 |
| 298 size_t InsertObject(Node* node) { |
| 299 size_t id = objects_.size(); |
| 300 objects_.push_back(node); |
| 301 return id; |
| 302 } |
| 303 |
| 304 private: |
| 305 ZoneVector<Node*> objects_; |
| 306 }; |
| 307 |
| 308 |
| 309 // Returns the number of instruction operands added to inputs. |
| 310 size_t AddOperandToStateValueDescriptor(StateValueDescriptor* desc, |
| 311 InstructionOperandVector* inputs, |
| 312 OperandGenerator* g, |
| 313 StateObjectCache* cache, Node* input, |
| 314 MachineType type, |
| 315 FrameStateInputKind kind, Zone* zone) { |
| 316 switch (input->opcode()) { |
| 317 case IrOpcode::kObjectState: { |
| 318 size_t id = cache->GetObjectId(input); |
| 319 if (id == StateObjectCache::kNotCached) { |
| 320 size_t entries = 0; |
| 321 id = cache->InsertObject(input); |
| 322 desc->fields().push_back(StateValueDescriptor::Recursive(zone, id)); |
| 323 StateValueDescriptor* new_desc = &desc->fields().back(); |
| 324 for (Edge edge : input->input_edges()) { |
| 325 entries += AddOperandToStateValueDescriptor( |
| 326 new_desc, inputs, g, cache, edge.to(), kMachAnyTagged, kind, |
| 327 zone); |
| 328 } |
| 329 return entries; |
| 330 } else { |
| 331 desc->fields().push_back(StateValueDescriptor::Duplicate(zone, id)); |
| 332 return 0; |
| 333 } |
| 334 break; |
| 335 } |
| 336 default: |
| 337 inputs->push_back(OperandForDeopt(g, input, kind)); |
| 338 desc->fields().push_back(StateValueDescriptor::Plain(zone, type)); |
| 339 return 1; |
280 } | 340 } |
281 } | 341 } |
282 | 342 |
283 | 343 |
284 void AddFrameStateInputs(Node* state, OperandGenerator* g, | 344 // Returns the number of instruction operands added to inputs. |
285 InstructionOperandVector* inputs, | 345 size_t AddInputsToFrameStateDescriptor(FrameStateDescriptor* desc, Node* state, |
286 FrameStateDescriptor* descriptor, | 346 OperandGenerator* g, |
287 FrameStateInputKind kind, Zone* zone) { | 347 StateObjectCache* cache, |
| 348 InstructionOperandVector* inputs, |
| 349 FrameStateInputKind kind, Zone* zone) { |
288 DCHECK_EQ(IrOpcode::kFrameState, state->op()->opcode()); | 350 DCHECK_EQ(IrOpcode::kFrameState, state->op()->opcode()); |
289 | 351 |
290 if (descriptor->outer_state()) { | 352 size_t entries = 0; |
291 AddFrameStateInputs(state->InputAt(kFrameStateOuterStateInput), g, inputs, | 353 size_t initial_size = inputs->size(); |
292 descriptor->outer_state(), kind, zone); | 354 USE(initial_size); // initial_size is only used for debug. |
| 355 |
| 356 if (desc->outer_state()) { |
| 357 entries += AddInputsToFrameStateDescriptor( |
| 358 desc->outer_state(), state->InputAt(kFrameStateOuterStateInput), g, |
| 359 cache, inputs, kind, zone); |
293 } | 360 } |
294 | 361 |
295 Node* parameters = state->InputAt(kFrameStateParametersInput); | 362 Node* parameters = state->InputAt(kFrameStateParametersInput); |
296 Node* locals = state->InputAt(kFrameStateLocalsInput); | 363 Node* locals = state->InputAt(kFrameStateLocalsInput); |
297 Node* stack = state->InputAt(kFrameStateStackInput); | 364 Node* stack = state->InputAt(kFrameStateStackInput); |
298 Node* context = state->InputAt(kFrameStateContextInput); | 365 Node* context = state->InputAt(kFrameStateContextInput); |
299 Node* function = state->InputAt(kFrameStateFunctionInput); | 366 Node* function = state->InputAt(kFrameStateFunctionInput); |
300 | 367 |
301 DCHECK_EQ(descriptor->parameters_count(), | 368 DCHECK_EQ(desc->parameters_count(), StateValuesAccess(parameters).size()); |
302 StateValuesAccess(parameters).size()); | 369 DCHECK_EQ(desc->locals_count(), StateValuesAccess(locals).size()); |
303 DCHECK_EQ(descriptor->locals_count(), StateValuesAccess(locals).size()); | 370 DCHECK_EQ(desc->stack_count(), StateValuesAccess(stack).size()); |
304 DCHECK_EQ(descriptor->stack_count(), StateValuesAccess(stack).size()); | |
305 | 371 |
306 ZoneVector<MachineType> types(zone); | 372 StateValueDescriptor* values_desc = desc->GetStateValueDescriptor(); |
307 types.reserve(descriptor->GetSize()); | 373 entries += AddOperandToStateValueDescriptor( |
308 | 374 values_desc, inputs, g, cache, function, kMachAnyTagged, kind, zone); |
309 size_t value_index = 0; | |
310 inputs->push_back(OperandForDeopt(g, function, kind)); | |
311 descriptor->SetType(value_index++, kMachAnyTagged); | |
312 for (StateValuesAccess::TypedNode input_node : | 375 for (StateValuesAccess::TypedNode input_node : |
313 StateValuesAccess(parameters)) { | 376 StateValuesAccess(parameters)) { |
314 inputs->push_back(OperandForDeopt(g, input_node.node, kind)); | 377 entries += AddOperandToStateValueDescriptor(values_desc, inputs, g, cache, |
315 descriptor->SetType(value_index++, input_node.type); | 378 input_node.node, |
| 379 input_node.type, kind, zone); |
316 } | 380 } |
317 if (descriptor->HasContext()) { | 381 if (desc->HasContext()) { |
318 inputs->push_back(OperandForDeopt(g, context, kind)); | 382 entries += AddOperandToStateValueDescriptor( |
319 descriptor->SetType(value_index++, kMachAnyTagged); | 383 values_desc, inputs, g, cache, context, kMachAnyTagged, kind, zone); |
320 } | 384 } |
321 for (StateValuesAccess::TypedNode input_node : StateValuesAccess(locals)) { | 385 for (StateValuesAccess::TypedNode input_node : StateValuesAccess(locals)) { |
322 inputs->push_back(OperandForDeopt(g, input_node.node, kind)); | 386 entries += AddOperandToStateValueDescriptor(values_desc, inputs, g, cache, |
323 descriptor->SetType(value_index++, input_node.type); | 387 input_node.node, |
| 388 input_node.type, kind, zone); |
324 } | 389 } |
325 for (StateValuesAccess::TypedNode input_node : StateValuesAccess(stack)) { | 390 for (StateValuesAccess::TypedNode input_node : StateValuesAccess(stack)) { |
326 inputs->push_back(OperandForDeopt(g, input_node.node, kind)); | 391 entries += AddOperandToStateValueDescriptor(values_desc, inputs, g, cache, |
327 descriptor->SetType(value_index++, input_node.type); | 392 input_node.node, |
| 393 input_node.type, kind, zone); |
328 } | 394 } |
329 DCHECK(value_index == descriptor->GetSize()); | 395 DCHECK_EQ(initial_size + entries, inputs->size()); |
| 396 return entries; |
330 } | 397 } |
331 | 398 |
332 } // namespace | 399 } // namespace |
333 | 400 |
334 | 401 |
335 // An internal helper class for generating the operands to calls. | 402 // An internal helper class for generating the operands to calls. |
336 // TODO(bmeurer): Get rid of the CallBuffer business and make | 403 // TODO(bmeurer): Get rid of the CallBuffer business and make |
337 // InstructionSelector::VisitCall platform independent instead. | 404 // InstructionSelector::VisitCall platform independent instead. |
338 struct CallBuffer { | 405 struct CallBuffer { |
339 CallBuffer(Zone* zone, const CallDescriptor* descriptor, | 406 CallBuffer(Zone* zone, const CallDescriptor* descriptor, |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 // The target is ignored, but we still need to pass a value here. | 518 // The target is ignored, but we still need to pass a value here. |
452 buffer->instruction_args.push_back(g.UseImmediate(callee)); | 519 buffer->instruction_args.push_back(g.UseImmediate(callee)); |
453 break; | 520 break; |
454 } | 521 } |
455 DCHECK_EQ(1u, buffer->instruction_args.size()); | 522 DCHECK_EQ(1u, buffer->instruction_args.size()); |
456 | 523 |
457 // If the call needs a frame state, we insert the state information as | 524 // If the call needs a frame state, we insert the state information as |
458 // follows (n is the number of value inputs to the frame state): | 525 // follows (n is the number of value inputs to the frame state): |
459 // arg 1 : deoptimization id. | 526 // arg 1 : deoptimization id. |
460 // arg 2 - arg (n + 1) : value inputs to the frame state. | 527 // arg 2 - arg (n + 1) : value inputs to the frame state. |
| 528 size_t frame_state_entries = 0; |
| 529 USE(frame_state_entries); // frame_state_entries is only used for debug. |
461 if (buffer->frame_state_descriptor != NULL) { | 530 if (buffer->frame_state_descriptor != NULL) { |
462 InstructionSequence::StateId state_id = | 531 InstructionSequence::StateId state_id = |
463 sequence()->AddFrameStateDescriptor(buffer->frame_state_descriptor); | 532 sequence()->AddFrameStateDescriptor(buffer->frame_state_descriptor); |
464 buffer->instruction_args.push_back(g.TempImmediate(state_id.ToInt())); | 533 buffer->instruction_args.push_back(g.TempImmediate(state_id.ToInt())); |
465 | 534 |
466 Node* frame_state = | 535 Node* frame_state = |
467 call->InputAt(static_cast<int>(buffer->descriptor->InputCount())); | 536 call->InputAt(static_cast<int>(buffer->descriptor->InputCount())); |
468 AddFrameStateInputs(frame_state, &g, &buffer->instruction_args, | 537 |
469 buffer->frame_state_descriptor, | 538 StateObjectCache cache(instruction_zone()); |
470 FrameStateInputKind::kStackSlot, instruction_zone()); | 539 |
| 540 frame_state_entries = |
| 541 1 + AddInputsToFrameStateDescriptor( |
| 542 buffer->frame_state_descriptor, frame_state, &g, &cache, |
| 543 &buffer->instruction_args, FrameStateInputKind::kStackSlot, |
| 544 instruction_zone()); |
| 545 |
| 546 DCHECK_EQ(1 + frame_state_entries, buffer->instruction_args.size()); |
471 } | 547 } |
472 DCHECK(1 + buffer->frame_state_value_count() == | |
473 buffer->instruction_args.size()); | |
474 | 548 |
475 size_t input_count = static_cast<size_t>(buffer->input_count()); | 549 size_t input_count = static_cast<size_t>(buffer->input_count()); |
476 | 550 |
477 // Split the arguments into pushed_nodes and instruction_args. Pushed | 551 // Split the arguments into pushed_nodes and instruction_args. Pushed |
478 // arguments require an explicit push instruction before the call and do | 552 // arguments require an explicit push instruction before the call and do |
479 // not appear as arguments to the call. Everything else ends up | 553 // not appear as arguments to the call. Everything else ends up |
480 // as an InstructionOperand argument to the call. | 554 // as an InstructionOperand argument to the call. |
481 auto iter(call->inputs().begin()); | 555 auto iter(call->inputs().begin()); |
482 size_t pushed_count = 0; | 556 size_t pushed_count = 0; |
483 bool call_tail = (flags & kCallTail) != 0; | 557 bool call_tail = (flags & kCallTail) != 0; |
(...skipping 15 matching lines...) Expand all Loading... |
499 buffer->pushed_nodes.resize(stack_index + 1, NULL); | 573 buffer->pushed_nodes.resize(stack_index + 1, NULL); |
500 } | 574 } |
501 DCHECK(!buffer->pushed_nodes[stack_index]); | 575 DCHECK(!buffer->pushed_nodes[stack_index]); |
502 buffer->pushed_nodes[stack_index] = *iter; | 576 buffer->pushed_nodes[stack_index] = *iter; |
503 pushed_count++; | 577 pushed_count++; |
504 } else { | 578 } else { |
505 buffer->instruction_args.push_back(op); | 579 buffer->instruction_args.push_back(op); |
506 } | 580 } |
507 } | 581 } |
508 DCHECK_EQ(input_count, buffer->instruction_args.size() + pushed_count - | 582 DCHECK_EQ(input_count, buffer->instruction_args.size() + pushed_count - |
509 buffer->frame_state_value_count()); | 583 frame_state_entries); |
510 if (V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK && call_tail && | 584 if (V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK && call_tail && |
511 stack_param_delta != 0) { | 585 stack_param_delta != 0) { |
512 // For tail calls that change the size of their parameter list and keep | 586 // For tail calls that change the size of their parameter list and keep |
513 // their return address on the stack, move the return address to just above | 587 // their return address on the stack, move the return address to just above |
514 // the parameters. | 588 // the parameters. |
515 LinkageLocation saved_return_location = | 589 LinkageLocation saved_return_location = |
516 LinkageLocation::ForSavedCallerReturnAddress(); | 590 LinkageLocation::ForSavedCallerReturnAddress(); |
517 InstructionOperand return_address = | 591 InstructionOperand return_address = |
518 g.UsePointerLocation(LinkageLocation::ConvertToTailCallerLocation( | 592 g.UsePointerLocation(LinkageLocation::ConvertToTailCallerLocation( |
519 saved_return_location, stack_param_delta), | 593 saved_return_location, stack_param_delta), |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
705 return MarkAsReference(node), VisitConstant(node); | 779 return MarkAsReference(node), VisitConstant(node); |
706 case IrOpcode::kNumberConstant: { | 780 case IrOpcode::kNumberConstant: { |
707 double value = OpParameter<double>(node); | 781 double value = OpParameter<double>(node); |
708 if (!IsSmiDouble(value)) MarkAsReference(node); | 782 if (!IsSmiDouble(value)) MarkAsReference(node); |
709 return VisitConstant(node); | 783 return VisitConstant(node); |
710 } | 784 } |
711 case IrOpcode::kCall: | 785 case IrOpcode::kCall: |
712 return VisitCall(node); | 786 return VisitCall(node); |
713 case IrOpcode::kFrameState: | 787 case IrOpcode::kFrameState: |
714 case IrOpcode::kStateValues: | 788 case IrOpcode::kStateValues: |
| 789 case IrOpcode::kObjectState: |
715 return; | 790 return; |
716 case IrOpcode::kLoad: { | 791 case IrOpcode::kLoad: { |
717 LoadRepresentation rep = OpParameter<LoadRepresentation>(node); | 792 LoadRepresentation rep = OpParameter<LoadRepresentation>(node); |
718 MarkAsRepresentation(rep, node); | 793 MarkAsRepresentation(rep, node); |
719 return VisitLoad(node); | 794 return VisitLoad(node); |
720 } | 795 } |
721 case IrOpcode::kStore: | 796 case IrOpcode::kStore: |
722 return VisitStore(node); | 797 return VisitStore(node); |
723 case IrOpcode::kWord32And: | 798 case IrOpcode::kWord32And: |
724 return MarkAsWord32(node), VisitWord32And(node); | 799 return MarkAsWord32(node), VisitWord32And(node); |
(...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1400 } | 1475 } |
1401 Emit(kArchRet, 0, nullptr, ret_count, value_locations); | 1476 Emit(kArchRet, 0, nullptr, ret_count, value_locations); |
1402 } | 1477 } |
1403 } | 1478 } |
1404 | 1479 |
1405 | 1480 |
1406 void InstructionSelector::VisitDeoptimize(Node* value) { | 1481 void InstructionSelector::VisitDeoptimize(Node* value) { |
1407 OperandGenerator g(this); | 1482 OperandGenerator g(this); |
1408 | 1483 |
1409 FrameStateDescriptor* desc = GetFrameStateDescriptor(value); | 1484 FrameStateDescriptor* desc = GetFrameStateDescriptor(value); |
1410 size_t arg_count = desc->GetTotalSize() + 1; // Include deopt id. | |
1411 | 1485 |
1412 InstructionOperandVector args(instruction_zone()); | 1486 InstructionOperandVector args(instruction_zone()); |
1413 args.reserve(arg_count); | 1487 args.reserve(desc->GetTotalSize() + 1); // Include deopt id. |
1414 | 1488 |
1415 InstructionSequence::StateId state_id = | 1489 InstructionSequence::StateId state_id = |
1416 sequence()->AddFrameStateDescriptor(desc); | 1490 sequence()->AddFrameStateDescriptor(desc); |
1417 args.push_back(g.TempImmediate(state_id.ToInt())); | 1491 args.push_back(g.TempImmediate(state_id.ToInt())); |
1418 | 1492 |
1419 AddFrameStateInputs(value, &g, &args, desc, FrameStateInputKind::kAny, | 1493 StateObjectCache cache(instruction_zone()); |
1420 instruction_zone()); | |
1421 | 1494 |
1422 DCHECK_EQ(args.size(), arg_count); | 1495 AddInputsToFrameStateDescriptor(desc, value, &g, &cache, &args, |
| 1496 FrameStateInputKind::kAny, |
| 1497 instruction_zone()); |
1423 | 1498 |
1424 Emit(kArchDeoptimize, 0, nullptr, arg_count, &args.front(), 0, nullptr); | 1499 Emit(kArchDeoptimize, 0, nullptr, args.size(), &args.front(), 0, nullptr); |
1425 } | 1500 } |
1426 | 1501 |
1427 | 1502 |
1428 void InstructionSelector::VisitThrow(Node* value) { | 1503 void InstructionSelector::VisitThrow(Node* value) { |
1429 OperandGenerator g(this); | 1504 OperandGenerator g(this); |
1430 Emit(kArchNop, g.NoOutput()); // TODO(titzer) | 1505 Emit(kArchNop, g.NoOutput()); // TODO(titzer) |
1431 } | 1506 } |
1432 | 1507 |
1433 | 1508 |
1434 FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor( | 1509 FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor( |
(...skipping 21 matching lines...) Expand all Loading... |
1456 return new (instruction_zone()) FrameStateDescriptor( | 1531 return new (instruction_zone()) FrameStateDescriptor( |
1457 instruction_zone(), state_info.type(), state_info.bailout_id(), | 1532 instruction_zone(), state_info.type(), state_info.bailout_id(), |
1458 state_info.state_combine(), parameters, locals, stack, | 1533 state_info.state_combine(), parameters, locals, stack, |
1459 state_info.shared_info(), outer_state); | 1534 state_info.shared_info(), outer_state); |
1460 } | 1535 } |
1461 | 1536 |
1462 | 1537 |
1463 } // namespace compiler | 1538 } // namespace compiler |
1464 } // namespace internal | 1539 } // namespace internal |
1465 } // namespace v8 | 1540 } // namespace v8 |
OLD | NEW |