| 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 "test/unittests/compiler/instruction-selector-unittest.h" | 5 #include "test/unittests/compiler/instruction-selector-unittest.h" |
| 6 | 6 |
| 7 #include "src/compiler/graph.h" | 7 #include "src/compiler/graph.h" |
| 8 #include "src/compiler/schedule.h" | 8 #include "src/compiler/schedule.h" |
| 9 #include "src/flags.h" | 9 #include "src/flags.h" |
| 10 #include "test/unittests/compiler/compiler-test-utils.h" | 10 #include "test/unittests/compiler/compiler-test-utils.h" |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 | 355 |
| 356 ZoneVector<MachineType> int32_type(1, kMachInt32, zone()); | 356 ZoneVector<MachineType> int32_type(1, kMachInt32, zone()); |
| 357 ZoneVector<MachineType> empty_types(zone()); | 357 ZoneVector<MachineType> empty_types(zone()); |
| 358 | 358 |
| 359 Node* parameters = | 359 Node* parameters = |
| 360 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(1)); | 360 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(1)); |
| 361 Node* locals = m.NewNode(m.common()->TypedStateValues(&empty_types)); | 361 Node* locals = m.NewNode(m.common()->TypedStateValues(&empty_types)); |
| 362 Node* stack = m.NewNode(m.common()->TypedStateValues(&empty_types)); | 362 Node* stack = m.NewNode(m.common()->TypedStateValues(&empty_types)); |
| 363 Node* context_dummy = m.Int32Constant(0); | 363 Node* context_dummy = m.Int32Constant(0); |
| 364 | 364 |
| 365 Node* state_node = m.NewNode( | 365 Node* state_node = |
| 366 m.common()->FrameState(JS_FRAME, bailout_id, | 366 m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id, |
| 367 OutputFrameStateCombine::Push()), | 367 OutputFrameStateCombine::Push()), |
| 368 parameters, locals, stack, context_dummy, m.UndefinedConstant()); | 368 parameters, locals, stack, context_dummy, function_node, |
| 369 m.UndefinedConstant()); |
| 369 Node* call = m.CallJS0(function_node, receiver, context, state_node); | 370 Node* call = m.CallJS0(function_node, receiver, context, state_node); |
| 370 m.Return(call); | 371 m.Return(call); |
| 371 | 372 |
| 372 Stream s = m.Build(kAllExceptNopInstructions); | 373 Stream s = m.Build(kAllExceptNopInstructions); |
| 373 | 374 |
| 374 // Skip until kArchCallJSFunction. | 375 // Skip until kArchCallJSFunction. |
| 375 size_t index = 0; | 376 size_t index = 0; |
| 376 for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction; | 377 for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction; |
| 377 index++) { | 378 index++) { |
| 378 } | 379 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 403 | 404 |
| 404 // Build frame state for the state before the call. | 405 // Build frame state for the state before the call. |
| 405 Node* parameters = | 406 Node* parameters = |
| 406 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43)); | 407 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43)); |
| 407 Node* locals = m.NewNode(m.common()->TypedStateValues(&float64_type), | 408 Node* locals = m.NewNode(m.common()->TypedStateValues(&float64_type), |
| 408 m.Float64Constant(0.5)); | 409 m.Float64Constant(0.5)); |
| 409 Node* stack = m.NewNode(m.common()->TypedStateValues(&tagged_type), | 410 Node* stack = m.NewNode(m.common()->TypedStateValues(&tagged_type), |
| 410 m.UndefinedConstant()); | 411 m.UndefinedConstant()); |
| 411 | 412 |
| 412 Node* context_sentinel = m.Int32Constant(0); | 413 Node* context_sentinel = m.Int32Constant(0); |
| 413 Node* frame_state_before = m.NewNode( | 414 Node* frame_state_before = |
| 414 m.common()->FrameState(JS_FRAME, bailout_id_before, | 415 m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before, |
| 415 OutputFrameStateCombine::Push()), | 416 OutputFrameStateCombine::Push()), |
| 416 parameters, locals, stack, context_sentinel, m.UndefinedConstant()); | 417 parameters, locals, stack, context_sentinel, function_node, |
| 418 m.UndefinedConstant()); |
| 417 | 419 |
| 418 // Build the call. | 420 // Build the call. |
| 419 Node* call = m.CallFunctionStub0(function_node, receiver, context, | 421 Node* call = m.CallFunctionStub0(function_node, receiver, context, |
| 420 frame_state_before, CALL_AS_METHOD); | 422 frame_state_before, CALL_AS_METHOD); |
| 421 | 423 |
| 422 m.Return(call); | 424 m.Return(call); |
| 423 | 425 |
| 424 Stream s = m.Build(kAllExceptNopInstructions); | 426 Stream s = m.Build(kAllExceptNopInstructions); |
| 425 | 427 |
| 426 // Skip until kArchCallJSFunction. | 428 // Skip until kArchCallJSFunction. |
| 427 size_t index = 0; | 429 size_t index = 0; |
| 428 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; | 430 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; |
| 429 index++) { | 431 index++) { |
| 430 } | 432 } |
| 431 // Now we should have two instructions: call, return. | 433 // Now we should have two instructions: call, return. |
| 432 ASSERT_EQ(index + 2, s.size()); | 434 ASSERT_EQ(index + 2, s.size()); |
| 433 | 435 |
| 434 // Check the call instruction | 436 // Check the call instruction |
| 435 const Instruction* call_instr = s[index++]; | 437 const Instruction* call_instr = s[index++]; |
| 436 EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); | 438 EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); |
| 437 size_t num_operands = | 439 size_t num_operands = |
| 438 1 + // Code object. | 440 1 + // Code object. |
| 439 1 + | 441 1 + |
| 440 4 + // Frame state deopt id + one input for each value in frame state. | 442 5 + // Frame state deopt id + one input for each value in frame state. |
| 441 1 + // Function. | 443 1 + // Function. |
| 442 1; // Context. | 444 1; // Context. |
| 443 ASSERT_EQ(num_operands, call_instr->InputCount()); | 445 ASSERT_EQ(num_operands, call_instr->InputCount()); |
| 444 | 446 |
| 445 // Code object. | 447 // Code object. |
| 446 EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); | 448 EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); |
| 447 | 449 |
| 448 // Deoptimization id. | 450 // Deoptimization id. |
| 449 int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); | 451 int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); |
| 450 FrameStateDescriptor* desc_before = | 452 FrameStateDescriptor* desc_before = |
| 451 s.GetFrameStateDescriptor(deopt_id_before); | 453 s.GetFrameStateDescriptor(deopt_id_before); |
| 452 EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); | 454 EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); |
| 453 EXPECT_EQ(OutputFrameStateCombine::kPushOutput, | 455 EXPECT_EQ(OutputFrameStateCombine::kPushOutput, |
| 454 desc_before->state_combine().kind()); | 456 desc_before->state_combine().kind()); |
| 455 EXPECT_EQ(1u, desc_before->parameters_count()); | 457 EXPECT_EQ(1u, desc_before->parameters_count()); |
| 456 EXPECT_EQ(1u, desc_before->locals_count()); | 458 EXPECT_EQ(1u, desc_before->locals_count()); |
| 457 EXPECT_EQ(1u, desc_before->stack_count()); | 459 EXPECT_EQ(1u, desc_before->stack_count()); |
| 458 EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2))); | 460 EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(3))); |
| 459 EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3))); // This should be a context. | 461 EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(4))); // This should be a context. |
| 460 // We inserted 0 here. | 462 // We inserted 0 here. |
| 461 EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(4))); | 463 EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(5))); |
| 462 EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(5))->IsUndefined()); | 464 EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(6))->IsUndefined()); |
| 463 EXPECT_EQ(kMachInt32, desc_before->GetType(0)); | 465 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(0)); // function is always |
| 464 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1)); // context is always | |
| 465 // tagged/any. | 466 // tagged/any. |
| 466 EXPECT_EQ(kMachFloat64, desc_before->GetType(2)); | 467 EXPECT_EQ(kMachInt32, desc_before->GetType(1)); |
| 467 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(3)); | 468 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(2)); // context is always |
| 469 // tagged/any. |
| 470 EXPECT_EQ(kMachFloat64, desc_before->GetType(3)); |
| 471 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(4)); |
| 468 | 472 |
| 469 // Function. | 473 // Function. |
| 470 EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(6))); | 474 EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(7))); |
| 471 // Context. | 475 // Context. |
| 472 EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(7))); | 476 EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(8))); |
| 473 | 477 |
| 474 EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); | 478 EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); |
| 475 | 479 |
| 476 EXPECT_EQ(index, s.size()); | 480 EXPECT_EQ(index, s.size()); |
| 477 } | 481 } |
| 478 | 482 |
| 479 | 483 |
| 480 TARGET_TEST_F(InstructionSelectorTest, | 484 TARGET_TEST_F(InstructionSelectorTest, |
| 481 CallFunctionStubDeoptRecursiveFrameState) { | 485 CallFunctionStubDeoptRecursiveFrameState) { |
| 482 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged, | 486 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 494 ZoneVector<MachineType> int32x2_type(2, kMachInt32, zone()); | 498 ZoneVector<MachineType> int32x2_type(2, kMachInt32, zone()); |
| 495 ZoneVector<MachineType> float64_type(1, kMachFloat64, zone()); | 499 ZoneVector<MachineType> float64_type(1, kMachFloat64, zone()); |
| 496 | 500 |
| 497 // Build frame state for the state before the call. | 501 // Build frame state for the state before the call. |
| 498 Node* parameters = | 502 Node* parameters = |
| 499 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(63)); | 503 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(63)); |
| 500 Node* locals = | 504 Node* locals = |
| 501 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(64)); | 505 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(64)); |
| 502 Node* stack = | 506 Node* stack = |
| 503 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(65)); | 507 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(65)); |
| 504 Node* frame_state_parent = | 508 Node* frame_state_parent = m.NewNode( |
| 505 m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent, | 509 m.common()->FrameState(JS_FRAME, bailout_id_parent, |
| 506 OutputFrameStateCombine::Ignore()), | 510 OutputFrameStateCombine::Ignore()), |
| 507 parameters, locals, stack, context, m.UndefinedConstant()); | 511 parameters, locals, stack, context, function_node, m.UndefinedConstant()); |
| 508 | 512 |
| 509 Node* context2 = m.Int32Constant(46); | 513 Node* context2 = m.Int32Constant(46); |
| 510 Node* parameters2 = | 514 Node* parameters2 = |
| 511 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43)); | 515 m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43)); |
| 512 Node* locals2 = m.NewNode(m.common()->TypedStateValues(&float64_type), | 516 Node* locals2 = m.NewNode(m.common()->TypedStateValues(&float64_type), |
| 513 m.Float64Constant(0.25)); | 517 m.Float64Constant(0.25)); |
| 514 Node* stack2 = m.NewNode(m.common()->TypedStateValues(&int32x2_type), | 518 Node* stack2 = m.NewNode(m.common()->TypedStateValues(&int32x2_type), |
| 515 m.Int32Constant(44), m.Int32Constant(45)); | 519 m.Int32Constant(44), m.Int32Constant(45)); |
| 516 Node* frame_state_before = | 520 Node* frame_state_before = |
| 517 m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before, | 521 m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before, |
| 518 OutputFrameStateCombine::Push()), | 522 OutputFrameStateCombine::Push()), |
| 519 parameters2, locals2, stack2, context2, frame_state_parent); | 523 parameters2, locals2, stack2, context2, function_node, |
| 524 frame_state_parent); |
| 520 | 525 |
| 521 // Build the call. | 526 // Build the call. |
| 522 Node* call = m.CallFunctionStub0(function_node, receiver, context2, | 527 Node* call = m.CallFunctionStub0(function_node, receiver, context2, |
| 523 frame_state_before, CALL_AS_METHOD); | 528 frame_state_before, CALL_AS_METHOD); |
| 524 | 529 |
| 525 m.Return(call); | 530 m.Return(call); |
| 526 | 531 |
| 527 Stream s = m.Build(kAllExceptNopInstructions); | 532 Stream s = m.Build(kAllExceptNopInstructions); |
| 528 | 533 |
| 529 // Skip until kArchCallJSFunction. | 534 // Skip until kArchCallJSFunction. |
| 530 size_t index = 0; | 535 size_t index = 0; |
| 531 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; | 536 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; |
| 532 index++) { | 537 index++) { |
| 533 } | 538 } |
| 534 // Now we should have three instructions: call, return. | 539 // Now we should have three instructions: call, return. |
| 535 EXPECT_EQ(index + 2, s.size()); | 540 EXPECT_EQ(index + 2, s.size()); |
| 536 | 541 |
| 537 // Check the call instruction | 542 // Check the call instruction |
| 538 const Instruction* call_instr = s[index++]; | 543 const Instruction* call_instr = s[index++]; |
| 539 EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); | 544 EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); |
| 540 size_t num_operands = | 545 size_t num_operands = |
| 541 1 + // Code object. | 546 1 + // Code object. |
| 542 1 + // Frame state deopt id | 547 1 + // Frame state deopt id |
| 543 5 + // One input for each value in frame state + context. | 548 6 + // One input for each value in frame state + context. |
| 544 4 + // One input for each value in the parent frame state + context. | 549 5 + // One input for each value in the parent frame state + context. |
| 545 1 + // Function. | 550 1 + // Function. |
| 546 1; // Context. | 551 1; // Context. |
| 547 EXPECT_EQ(num_operands, call_instr->InputCount()); | 552 EXPECT_EQ(num_operands, call_instr->InputCount()); |
| 548 // Code object. | 553 // Code object. |
| 549 EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); | 554 EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); |
| 550 | 555 |
| 551 // Deoptimization id. | 556 // Deoptimization id. |
| 552 int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); | 557 int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); |
| 553 FrameStateDescriptor* desc_before = | 558 FrameStateDescriptor* desc_before = |
| 554 s.GetFrameStateDescriptor(deopt_id_before); | 559 s.GetFrameStateDescriptor(deopt_id_before); |
| 555 FrameStateDescriptor* desc_before_outer = desc_before->outer_state(); | 560 FrameStateDescriptor* desc_before_outer = desc_before->outer_state(); |
| 556 EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); | 561 EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); |
| 557 EXPECT_EQ(1u, desc_before_outer->parameters_count()); | 562 EXPECT_EQ(1u, desc_before_outer->parameters_count()); |
| 558 EXPECT_EQ(1u, desc_before_outer->locals_count()); | 563 EXPECT_EQ(1u, desc_before_outer->locals_count()); |
| 559 EXPECT_EQ(1u, desc_before_outer->stack_count()); | 564 EXPECT_EQ(1u, desc_before_outer->stack_count()); |
| 560 // Values from parent environment. | 565 // Values from parent environment. |
| 561 EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2))); | 566 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(0)); |
| 562 EXPECT_EQ(kMachInt32, desc_before_outer->GetType(0)); | 567 EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(3))); |
| 568 EXPECT_EQ(kMachInt32, desc_before_outer->GetType(1)); |
| 563 // Context: | 569 // Context: |
| 564 EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3))); | 570 EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(4))); |
| 565 EXPECT_EQ(kMachAnyTagged, desc_before_outer->GetType(1)); | 571 EXPECT_EQ(kMachAnyTagged, desc_before_outer->GetType(2)); |
| 566 EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4))); | 572 EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(5))); |
| 567 EXPECT_EQ(kMachInt32, desc_before_outer->GetType(2)); | |
| 568 EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5))); | |
| 569 EXPECT_EQ(kMachInt32, desc_before_outer->GetType(3)); | 573 EXPECT_EQ(kMachInt32, desc_before_outer->GetType(3)); |
| 574 EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(6))); |
| 575 EXPECT_EQ(kMachInt32, desc_before_outer->GetType(4)); |
| 570 // Values from the nested frame. | 576 // Values from the nested frame. |
| 571 EXPECT_EQ(1u, desc_before->parameters_count()); | 577 EXPECT_EQ(1u, desc_before->parameters_count()); |
| 572 EXPECT_EQ(1u, desc_before->locals_count()); | 578 EXPECT_EQ(1u, desc_before->locals_count()); |
| 573 EXPECT_EQ(2u, desc_before->stack_count()); | 579 EXPECT_EQ(2u, desc_before->stack_count()); |
| 574 EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6))); | 580 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(0)); |
| 575 EXPECT_EQ(kMachInt32, desc_before->GetType(0)); | 581 EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(8))); |
| 576 EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7))); | 582 EXPECT_EQ(kMachInt32, desc_before->GetType(1)); |
| 577 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1)); | 583 EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(9))); |
| 578 EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(8))); | 584 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(2)); |
| 579 EXPECT_EQ(kMachFloat64, desc_before->GetType(2)); | 585 EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(10))); |
| 580 EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(9))); | 586 EXPECT_EQ(kMachFloat64, desc_before->GetType(3)); |
| 581 EXPECT_EQ(kMachInt32, desc_before->GetType(3)); | 587 EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(11))); |
| 582 EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(10))); | |
| 583 EXPECT_EQ(kMachInt32, desc_before->GetType(4)); | 588 EXPECT_EQ(kMachInt32, desc_before->GetType(4)); |
| 589 EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(12))); |
| 590 EXPECT_EQ(kMachInt32, desc_before->GetType(5)); |
| 584 | 591 |
| 585 // Function. | 592 // Function. |
| 586 EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(11))); | 593 EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(13))); |
| 587 // Context. | 594 // Context. |
| 588 EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(12))); | 595 EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(14))); |
| 589 // Continuation. | 596 // Continuation. |
| 590 | 597 |
| 591 EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); | 598 EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); |
| 592 EXPECT_EQ(index, s.size()); | 599 EXPECT_EQ(index, s.size()); |
| 593 } | 600 } |
| 594 | 601 |
| 595 } // namespace compiler | 602 } // namespace compiler |
| 596 } // namespace internal | 603 } // namespace internal |
| 597 } // namespace v8 | 604 } // namespace v8 |
| OLD | NEW |