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

Side by Side Diff: src/codegen-ia32.cc

Issue 19622: Remove spills from most inlined runtime calls. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: Created 11 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | 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 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 3411 matching lines...) Expand 10 before | Expand all | Expand 10 after
3422 frame_->CallStub(&call_function, arg_count + 1); 3422 frame_->CallStub(&call_function, arg_count + 1);
3423 3423
3424 // Restore context and pop function from the stack. 3424 // Restore context and pop function from the stack.
3425 frame_->RestoreContextRegister(); 3425 frame_->RestoreContextRegister();
3426 __ mov(frame_->Top(), eax); 3426 __ mov(frame_->Top(), eax);
3427 } 3427 }
3428 3428
3429 3429
3430 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { 3430 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
3431 ASSERT(args->length() == 1); 3431 ASSERT(args->length() == 1);
3432 LoadAndSpill(args->at(0)); 3432 Load(args->at(0));
3433 frame_->EmitPop(eax); 3433 Result value = frame_->Pop();
3434 __ test(eax, Immediate(kSmiTagMask)); 3434 value.ToRegister();
3435 ASSERT(value.is_valid());
3436 __ test(value.reg(), Immediate(kSmiTagMask));
3437 value.Unuse();
3435 true_target()->Branch(zero); 3438 true_target()->Branch(zero);
3436 false_target()->Jump(); 3439 false_target()->Jump();
3437 } 3440 }
3438 3441
3439 3442
3440 void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) { 3443 void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) {
3441 // Conditionally generate a log call. 3444 // Conditionally generate a log call.
3442 // Args: 3445 // Args:
3443 // 0 (literal string): The type of logging (corresponds to the flags). 3446 // 0 (literal string): The type of logging (corresponds to the flags).
3444 // This is used to determine whether or not to generate the log call. 3447 // This is used to determine whether or not to generate the log call.
3445 // 1 (string): Format string. Access the string at argument index 2 3448 // 1 (string): Format string. Access the string at argument index 2
3446 // with '%2s' (see Logger::LogRuntime for all the formats). 3449 // with '%2s' (see Logger::LogRuntime for all the formats).
3447 // 2 (array): Arguments to the format string. 3450 // 2 (array): Arguments to the format string.
3448 ASSERT_EQ(args->length(), 3); 3451 ASSERT_EQ(args->length(), 3);
3449 #ifdef ENABLE_LOGGING_AND_PROFILING 3452 #ifdef ENABLE_LOGGING_AND_PROFILING
3450 if (ShouldGenerateLog(args->at(0))) { 3453 if (ShouldGenerateLog(args->at(0))) {
3451 LoadAndSpill(args->at(1)); 3454 Load(args->at(1));
3452 LoadAndSpill(args->at(2)); 3455 Load(args->at(2));
3453 frame_->CallRuntime(Runtime::kLog, 2); 3456 frame_->CallRuntime(Runtime::kLog, 2);
3454 } 3457 }
3455 #endif 3458 #endif
3456 // Finally, we're expected to leave a value on the top of the stack. 3459 // Finally, we're expected to leave a value on the top of the stack.
3457 frame_->EmitPush(Immediate(Factory::undefined_value())); 3460 frame_->Push(Factory::undefined_value());
3458 } 3461 }
3459 3462
3460 3463
3461 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { 3464 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
3462 ASSERT(args->length() == 1); 3465 ASSERT(args->length() == 1);
3463 LoadAndSpill(args->at(0)); 3466 Load(args->at(0));
3464 frame_->EmitPop(eax); 3467 Result value = frame_->Pop();
3465 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); 3468 value.ToRegister();
3469 ASSERT(value.is_valid());
3470 __ test(value.reg(), Immediate(kSmiTagMask | 0x80000000));
3471 value.Unuse();
3466 true_target()->Branch(zero); 3472 true_target()->Branch(zero);
3467 false_target()->Jump(); 3473 false_target()->Jump();
3468 } 3474 }
3469 3475
3470 3476
3471 // This generates code that performs a charCodeAt() call or returns 3477 // This generates code that performs a charCodeAt() call or returns
3472 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. 3478 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
3473 // It can handle flat and sliced strings, 8 and 16 bit characters and 3479 // It can handle flat and sliced strings, 8 and 16 bit characters and
3474 // cons strings where the answer is found in the left hand branch of the 3480 // cons strings where the answer is found in the left hand branch of the
3475 // cons. The slow case will flatten the string, which will ensure that 3481 // cons. The slow case will flatten the string, which will ensure that
3476 // the answer is in the left hand side the next time around. 3482 // the answer is in the left hand side the next time around.
3477 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { 3483 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
3484 VirtualFrame::SpilledScope spilled_scope(this);
3478 ASSERT(args->length() == 2); 3485 ASSERT(args->length() == 2);
3479 3486
3480 JumpTarget slow_case(this); 3487 JumpTarget slow_case(this);
3481 JumpTarget end(this); 3488 JumpTarget end(this);
3482 JumpTarget not_a_flat_string(this); 3489 JumpTarget not_a_flat_string(this);
3483 JumpTarget not_a_cons_string_either(this); 3490 JumpTarget not_a_cons_string_either(this);
3484 JumpTarget try_again_with_new_string(this, JumpTarget::BIDIRECTIONAL); 3491 JumpTarget try_again_with_new_string(this, JumpTarget::BIDIRECTIONAL);
3485 JumpTarget ascii_string(this); 3492 JumpTarget ascii_string(this);
3486 JumpTarget got_char_code(this); 3493 JumpTarget got_char_code(this);
3487 3494
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
3580 3587
3581 slow_case.Bind(); 3588 slow_case.Bind();
3582 frame_->EmitPush(Immediate(Factory::undefined_value())); 3589 frame_->EmitPush(Immediate(Factory::undefined_value()));
3583 3590
3584 end.Bind(); 3591 end.Bind();
3585 } 3592 }
3586 3593
3587 3594
3588 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { 3595 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
3589 ASSERT(args->length() == 1); 3596 ASSERT(args->length() == 1);
3590 LoadAndSpill(args->at(0)); 3597 Load(args->at(0));
3591 // We need the CC bits to come out as not_equal in the case where the 3598 Result value = frame_->Pop();
Kevin Millikin (Chromium) 2009/01/29 09:42:36 It's nice to get rid of this.
3592 // object is a smi. This can't be done with the usual test opcode so 3599 value.ToRegister();
3593 // we copy the object to ecx and do some destructive ops on it that 3600 ASSERT(value.is_valid());
3594 // result in the right CC bits. 3601 __ test(value.reg(), Immediate(kSmiTagMask));
3595 frame_->EmitPop(eax); 3602 false_target()->Branch(equal);
3596 __ mov(ecx, Operand(eax));
3597 __ and_(ecx, kSmiTagMask);
3598 __ xor_(ecx, kSmiTagMask);
3599 false_target()->Branch(not_equal);
3600 // It is a heap object - get map. 3603 // It is a heap object - get map.
3601 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); 3604 Result temp = allocator()->Allocate();
Kevin Millikin (Chromium) 2009/01/29 09:42:36 We will need to sort out the decision to spill an
3602 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); 3605 ASSERT(temp.is_valid());
3606 __ mov(temp.reg(), FieldOperand(value.reg(), HeapObject::kMapOffset));
3607 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
3603 // Check if the object is a JS array or not. 3608 // Check if the object is a JS array or not.
3604 __ cmp(eax, JS_ARRAY_TYPE); 3609 __ cmp(temp.reg(), JS_ARRAY_TYPE);
3610 value.Unuse();
3611 temp.Unuse();
3605 true_target()->Branch(equal); 3612 true_target()->Branch(equal);
3606 false_target()->Jump(); 3613 false_target()->Jump();
3607 } 3614 }
3608 3615
3609 3616
3610 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { 3617 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
3611 ASSERT(args->length() == 0); 3618 ASSERT(args->length() == 0);
3612 3619
3613 // Seed the result with the formal parameters count, which will be 3620 // Seed the result with the formal parameters count, which will be
Kevin Millikin (Chromium) 2009/01/29 09:42:36 I would reword this comment to be more explicit.
William Hesse 2012/05/07 09:36:09 Done.
3614 // used in case no arguments adaptor frame is found below the 3621 // used in case no arguments adaptor frame is found below the
3615 // current frame. 3622 // current frame.
3616 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); 3623 Result initial_value = allocator()->Allocate(eax);
3624 ASSERT(initial_value.is_valid());
3625 __ Set(initial_value.reg(),
3626 Immediate(Smi::FromInt(scope_->num_parameters())));
3617 3627
3618 // Call the shared stub to get to the arguments.length. 3628 // Call the shared stub to get to the arguments.length.
3619 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); 3629 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
3620 frame_->CallStub(&stub, 0); 3630 Result result = frame_->CallStub(&stub, &initial_value, 0);
3621 frame_->EmitPush(eax); 3631 frame_->Push(&result);
3622 } 3632 }
3623 3633
3624 3634
3625 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { 3635 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
3626 ASSERT(args->length() == 1); 3636 ASSERT(args->length() == 1);
3627 JumpTarget leave(this); 3637 JumpTarget leave(this);
3628 LoadAndSpill(args->at(0)); // Load the object. 3638 Load(args->at(0)); // Load the object.
3629 __ mov(eax, frame_->Top()); 3639 frame_->Dup();
3640 Result object = frame_->Pop();
3641 object.ToRegister();
3642 ASSERT(object.is_valid());
3630 // if (object->IsSmi()) return object. 3643 // if (object->IsSmi()) return object.
3631 __ test(eax, Immediate(kSmiTagMask)); 3644 __ test(object.reg(), Immediate(kSmiTagMask));
3632 leave.Branch(zero, taken); 3645 leave.Branch(zero, taken);
3633 // It is a heap object - get map. 3646 // It is a heap object - get map.
3634 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 3647 Result temp = allocator()->Allocate();
3635 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 3648 ASSERT(temp.is_valid());
3649 __ mov(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset));
3650 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
3636 // if (!object->IsJSValue()) return object. 3651 // if (!object->IsJSValue()) return object.
3637 __ cmp(ecx, JS_VALUE_TYPE); 3652 __ cmp(temp.reg(), JS_VALUE_TYPE);
3638 leave.Branch(not_equal, not_taken); 3653 leave.Branch(not_equal, not_taken);
3639 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); 3654 __ mov(temp.reg(), FieldOperand(object.reg(), JSValue::kValueOffset));
3640 __ mov(frame_->Top(), eax); 3655 object.Unuse();
3656 frame_->Drop();
3657 frame_->Push(&temp);
Kevin Millikin (Chromium) 2009/01/29 09:42:36 Can we avoid the drop/push sequence here by settin
William Hesse 2012/05/07 09:36:09 Done.
3641 leave.Bind(); 3658 leave.Bind();
3642 } 3659 }
3643 3660
3644 3661
3645 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { 3662 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
3663 VirtualFrame::SpilledScope spilled_scope(this);
3646 ASSERT(args->length() == 2); 3664 ASSERT(args->length() == 2);
3647 JumpTarget leave(this); 3665 JumpTarget leave(this);
3648 LoadAndSpill(args->at(0)); // Load the object. 3666 LoadAndSpill(args->at(0)); // Load the object.
3649 LoadAndSpill(args->at(1)); // Load the value. 3667 LoadAndSpill(args->at(1)); // Load the value.
3650 __ mov(eax, frame_->ElementAt(1)); 3668 __ mov(eax, frame_->ElementAt(1));
3651 __ mov(ecx, frame_->Top()); 3669 __ mov(ecx, frame_->Top());
3652 // if (object->IsSmi()) return object. 3670 // if (object->IsSmi()) return value.
3653 __ test(eax, Immediate(kSmiTagMask)); 3671 __ test(eax, Immediate(kSmiTagMask));
3654 leave.Branch(zero, taken); 3672 leave.Branch(zero, taken);
3655 // It is a heap object - get map. 3673 // It is a heap object - get map.
3656 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 3674 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3657 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 3675 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
3658 // if (!object->IsJSValue()) return object. 3676 // if (!object->IsJSValue()) return value.
3659 __ cmp(ebx, JS_VALUE_TYPE); 3677 __ cmp(ebx, JS_VALUE_TYPE);
3660 leave.Branch(not_equal, not_taken); 3678 leave.Branch(not_equal, not_taken);
3661 // Store the value. 3679 // Store the value.
3662 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); 3680 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx);
3663 // Update the write barrier. 3681 // Update the write barrier.
3664 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); 3682 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx);
3665 // Leave. 3683 // Leave.
3666 leave.Bind(); 3684 leave.Bind();
3667 __ mov(ecx, frame_->Top()); 3685 __ mov(ecx, frame_->Top());
3668 frame_->Drop(); 3686 frame_->Drop();
3669 __ mov(frame_->Top(), ecx); 3687 __ mov(frame_->Top(), ecx);
3670 } 3688 }
3671 3689
3672 3690
3673 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { 3691 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
3674 ASSERT(args->length() == 1); 3692 ASSERT(args->length() == 1);
3675 3693
3676 // Load the key onto the stack and set register eax to the formal 3694 // Load the key onto the stack and set register eax to the formal
3677 // parameters count for the currently executing function. 3695 // parameters count for the currently executing function.
3678 LoadAndSpill(args->at(0)); 3696 Load(args->at(0));
3679 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); 3697 Result parameters_count = allocator()->Allocate(eax);
3698 ASSERT(parameters_count.is_valid());
3699 __ Set(parameters_count.reg(),
3700 Immediate(Smi::FromInt(scope_->num_parameters())));
3680 3701
3681 // Call the shared stub to get to arguments[key]. 3702 // Call the shared stub to get to arguments[key].
3682 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); 3703 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
3683 frame_->CallStub(&stub, 0); 3704 Result result = frame_->CallStub(&stub, &parameters_count, 0);
3684 __ mov(frame_->Top(), eax); 3705 frame_->Drop();
Kevin Millikin (Chromium) 2009/01/29 09:42:36 Can we avoid the drop/push sequence here by settin
William Hesse 2012/05/07 09:36:09 Done.
3706 frame_->Push(&result);
3685 } 3707 }
3686 3708
3687 3709
3688 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { 3710 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
3689 ASSERT(args->length() == 2); 3711 ASSERT(args->length() == 2);
3690 3712
3691 // Load the two objects into registers and perform the comparison. 3713 // Load the two objects into registers and perform the comparison.
3692 LoadAndSpill(args->at(0)); 3714 Load(args->at(0));
3693 LoadAndSpill(args->at(1)); 3715 Load(args->at(1));
3694 frame_->EmitPop(eax); 3716 Result right = frame_->Pop();
3695 frame_->EmitPop(ecx); 3717 Result left = frame_->Pop();
3696 __ cmp(eax, Operand(ecx)); 3718 right.ToRegister();
3719 left.ToRegister();
Kevin Millikin (Chromium) 2009/01/29 09:42:36 I would rather not move left to a register, but ge
William Hesse 2012/05/07 09:36:09 What if right is a constant? Let's do this when w
3720 __ cmp(right.reg(), Operand(left.reg()));
3721 right.Unuse();
3722 left.Unuse();
3697 true_target()->Branch(equal); 3723 true_target()->Branch(equal);
3698 false_target()->Jump(); 3724 false_target()->Jump();
3699 } 3725 }
3700 3726
3701 3727
3702 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { 3728 void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
3703 VirtualFrame::SpilledScope spilled_scope(this);
3704 if (CheckForInlineRuntimeCall(node)) { 3729 if (CheckForInlineRuntimeCall(node)) {
3705 return; 3730 return;
3706 } 3731 }
3732 VirtualFrame::SpilledScope spilled_scope(this);
Kevin Millikin (Chromium) 2009/01/29 09:42:36 Double check that this is scope is gone once you u
3707 3733
3708 ZoneList<Expression*>* args = node->arguments(); 3734 ZoneList<Expression*>* args = node->arguments();
3709 Comment cmnt(masm_, "[ CallRuntime"); 3735 Comment cmnt(masm_, "[ CallRuntime");
3710 Runtime::Function* function = node->function(); 3736 Runtime::Function* function = node->function();
3711 3737
3712 if (function == NULL) { 3738 if (function == NULL) {
3713 // Prepare stack for calling JS runtime function. 3739 // Prepare stack for calling JS runtime function.
3714 frame_->EmitPush(Immediate(node->name())); 3740 frame_->EmitPush(Immediate(node->name()));
3715 // Push the builtins object found in the current global object. 3741 // Push the builtins object found in the current global object.
3716 __ mov(edx, GlobalObject()); 3742 __ mov(edx, GlobalObject());
(...skipping 2509 matching lines...) Expand 10 before | Expand all | Expand 10 after
6226 6252
6227 // Slow-case: Go through the JavaScript implementation. 6253 // Slow-case: Go through the JavaScript implementation.
6228 __ bind(&slow); 6254 __ bind(&slow);
6229 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 6255 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
6230 } 6256 }
6231 6257
6232 6258
6233 #undef __ 6259 #undef __
6234 6260
6235 } } // namespace v8::internal 6261 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698