Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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, ¶meters_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 Loading... | |
| 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 |
| OLD | NEW |