| 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 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 // condition code register and no value is pushed. If the condition code | 400 // condition code register and no value is pushed. If the condition code |
| 401 // register was set, has_cc() is true and cc_reg_ contains the condition to | 401 // register was set, has_cc() is true and cc_reg_ contains the condition to |
| 402 // test for 'true'. | 402 // test for 'true'. |
| 403 void CodeGenerator::LoadCondition(Expression* x, | 403 void CodeGenerator::LoadCondition(Expression* x, |
| 404 TypeofState typeof_state, | 404 TypeofState typeof_state, |
| 405 JumpTarget* true_target, | 405 JumpTarget* true_target, |
| 406 JumpTarget* false_target, | 406 JumpTarget* false_target, |
| 407 bool force_cc) { | 407 bool force_cc) { |
| 408 ASSERT(!in_spilled_code()); | 408 ASSERT(!in_spilled_code()); |
| 409 ASSERT(!has_cc()); | 409 ASSERT(!has_cc()); |
| 410 | 410 #ifdef DEBUG |
| 411 int original_height = frame_->height(); |
| 412 #endif |
| 411 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 413 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 412 Visit(x); | 414 Visit(x); |
| 413 } | 415 } |
| 414 | 416 |
| 415 if (force_cc && has_valid_frame() && !has_cc()) { | 417 if (force_cc && has_valid_frame() && !has_cc()) { |
| 416 // Convert the TOS value to a boolean in the condition code register. | 418 // Convert the TOS value to a boolean in the condition code register. |
| 417 VirtualFrame::SpilledScope spilled_scope(this); | |
| 418 ToBoolean(true_target, false_target); | 419 ToBoolean(true_target, false_target); |
| 419 } | 420 } |
| 420 | 421 |
| 421 ASSERT(!force_cc || frame_ == NULL || has_cc()); | 422 ASSERT(!force_cc || frame_ == NULL || has_cc()); |
| 423 ASSERT(!has_valid_frame() || |
| 424 (has_cc() && frame_->height() == original_height) || |
| 425 (!has_cc() && frame_->height() == original_height + 1)); |
| 422 } | 426 } |
| 423 | 427 |
| 424 | 428 |
| 425 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 429 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 430 #ifdef DEBUG |
| 431 int original_height = frame_->height(); |
| 432 #endif |
| 426 ASSERT(!in_spilled_code()); | 433 ASSERT(!in_spilled_code()); |
| 427 JumpTarget true_target(this); | 434 JumpTarget true_target(this); |
| 428 JumpTarget false_target(this); | 435 JumpTarget false_target(this); |
| 429 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 436 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 430 | 437 |
| 431 if (has_cc()) { | 438 if (has_cc()) { |
| 432 ASSERT(has_valid_frame()); | 439 ASSERT(has_valid_frame()); |
| 433 VirtualFrame::SpilledScope spilled_scope(this); | 440 VirtualFrame::SpilledScope spilled_scope(this); |
| 434 // Convert cc_reg_ into a boolean value. | 441 // Convert cc_reg_ into a boolean value. |
| 435 JumpTarget loaded(this); | 442 JumpTarget loaded(this); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 466 if (false_target.is_linked()) { | 473 if (false_target.is_linked()) { |
| 467 false_target.Bind(); | 474 false_target.Bind(); |
| 468 VirtualFrame::SpilledScope spilled_scope(this); | 475 VirtualFrame::SpilledScope spilled_scope(this); |
| 469 frame_->EmitPush(Immediate(Factory::false_value())); | 476 frame_->EmitPush(Immediate(Factory::false_value())); |
| 470 } | 477 } |
| 471 // A value is loaded on all paths reaching this point. | 478 // A value is loaded on all paths reaching this point. |
| 472 loaded.Bind(); | 479 loaded.Bind(); |
| 473 } | 480 } |
| 474 ASSERT(has_valid_frame()); | 481 ASSERT(has_valid_frame()); |
| 475 ASSERT(!has_cc()); | 482 ASSERT(!has_cc()); |
| 483 ASSERT(frame_->height() == original_height + 1); |
| 476 } | 484 } |
| 477 | 485 |
| 478 | 486 |
| 479 void CodeGenerator::LoadGlobal() { | 487 void CodeGenerator::LoadGlobal() { |
| 480 if (in_spilled_code()) { | 488 if (in_spilled_code()) { |
| 481 frame_->EmitPush(GlobalObject()); | 489 frame_->EmitPush(GlobalObject()); |
| 482 } else { | 490 } else { |
| 483 Result temp = allocator_->Allocate(); | 491 Result temp = allocator_->Allocate(); |
| 484 __ mov(temp.reg(), GlobalObject()); | 492 __ mov(temp.reg(), GlobalObject()); |
| 485 frame_->Push(&temp); | 493 frame_->Push(&temp); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 599 | 607 |
| 600 | 608 |
| 601 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and | 609 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and |
| 602 // convert it to a boolean in the condition code register or jump to | 610 // convert it to a boolean in the condition code register or jump to |
| 603 // 'false_target'/'true_target' as appropriate. | 611 // 'false_target'/'true_target' as appropriate. |
| 604 void CodeGenerator::ToBoolean(JumpTarget* true_target, | 612 void CodeGenerator::ToBoolean(JumpTarget* true_target, |
| 605 JumpTarget* false_target) { | 613 JumpTarget* false_target) { |
| 606 Comment cmnt(masm_, "[ ToBoolean"); | 614 Comment cmnt(masm_, "[ ToBoolean"); |
| 607 | 615 |
| 608 // The value to convert should be popped from the stack. | 616 // The value to convert should be popped from the stack. |
| 609 frame_->EmitPop(eax); | 617 Result value = frame_->Pop(); |
| 610 | 618 value.ToRegister(); |
| 611 // Fast case checks. | 619 // Fast case checks. |
| 612 | 620 |
| 613 // 'false' => false. | 621 // 'false' => false. |
| 614 __ cmp(eax, Factory::false_value()); | 622 __ cmp(value.reg(), Factory::false_value()); |
| 615 false_target->Branch(equal); | 623 false_target->Branch(equal); |
| 616 | 624 |
| 617 // 'true' => true. | 625 // 'true' => true. |
| 618 __ cmp(eax, Factory::true_value()); | 626 __ cmp(value.reg(), Factory::true_value()); |
| 619 true_target->Branch(equal); | 627 true_target->Branch(equal); |
| 620 | 628 |
| 621 // 'undefined' => false. | 629 // 'undefined' => false. |
| 622 __ cmp(eax, Factory::undefined_value()); | 630 __ cmp(value.reg(), Factory::undefined_value()); |
| 623 false_target->Branch(equal); | 631 false_target->Branch(equal); |
| 624 | 632 |
| 625 // Smi => false iff zero. | 633 // Smi => false iff zero. |
| 626 ASSERT(kSmiTag == 0); | 634 ASSERT(kSmiTag == 0); |
| 627 __ test(eax, Operand(eax)); | 635 __ test(value.reg(), Operand(value.reg())); |
| 628 false_target->Branch(zero); | 636 false_target->Branch(zero); |
| 629 __ test(eax, Immediate(kSmiTagMask)); | 637 __ test(value.reg(), Immediate(kSmiTagMask)); |
| 630 true_target->Branch(zero); | 638 true_target->Branch(zero); |
| 631 | 639 |
| 632 // Call the stub for all other cases. | 640 // Call the stub for all other cases. |
| 633 frame_->EmitPush(eax); // Undo the pop(eax) from above. | 641 frame_->Push(&value); // Undo the Pop() from above. |
| 634 ToBooleanStub stub; | 642 ToBooleanStub stub; |
| 635 frame_->CallStub(&stub, 1); | 643 frame_->CallStub(&stub, 1); |
| 636 // Convert the result (eax) to condition code. | 644 // Convert the result (eax) to condition code. |
| 645 Result temp = allocator_->Allocate(eax); |
| 646 ASSERT(temp.is_valid()); |
| 637 __ test(eax, Operand(eax)); | 647 __ test(eax, Operand(eax)); |
| 638 | 648 |
| 639 ASSERT(not_equal == not_zero); | 649 ASSERT(not_equal == not_zero); |
| 640 cc_reg_ = not_equal; | 650 cc_reg_ = not_equal; |
| 641 } | 651 } |
| 642 | 652 |
| 643 | 653 |
| 644 class FloatingPointHelper : public AllStatic { | 654 class FloatingPointHelper : public AllStatic { |
| 645 public: | 655 public: |
| 646 // Code pattern for loading floating point values. Input values must | 656 // Code pattern for loading floating point values. Input values must |
| (...skipping 3366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4013 } | 4023 } |
| 4014 | 4024 |
| 4015 // Postfix: Discard the new value and use the old. | 4025 // Postfix: Discard the new value and use the old. |
| 4016 if (is_postfix) { | 4026 if (is_postfix) { |
| 4017 frame_->Drop(); | 4027 frame_->Drop(); |
| 4018 } | 4028 } |
| 4019 } | 4029 } |
| 4020 | 4030 |
| 4021 | 4031 |
| 4022 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 4032 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 4023 VirtualFrame::SpilledScope spilled_scope(this); | |
| 4024 // Note that due to an optimization in comparison operations (typeof | 4033 // Note that due to an optimization in comparison operations (typeof |
| 4025 // compared to a string literal), we can evaluate a binary expression such | 4034 // compared to a string literal), we can evaluate a binary expression such |
| 4026 // as AND or OR and not leave a value on the frame or in the cc register. | 4035 // as AND or OR and not leave a value on the frame or in the cc register. |
| 4027 Comment cmnt(masm_, "[ BinaryOperation"); | 4036 Comment cmnt(masm_, "[ BinaryOperation"); |
| 4028 Token::Value op = node->op(); | 4037 Token::Value op = node->op(); |
| 4029 | 4038 |
| 4030 // According to ECMA-262 section 11.11, page 58, the binary logical | 4039 // According to ECMA-262 section 11.11, page 58, the binary logical |
| 4031 // operators must yield the result of one of the two expressions | 4040 // operators must yield the result of one of the two expressions |
| 4032 // before any ToBoolean() conversions. This means that the value | 4041 // before any ToBoolean() conversions. This means that the value |
| 4033 // produced by a && or || operator is not necessarily a boolean. | 4042 // produced by a && or || operator is not necessarily a boolean. |
| 4034 | 4043 |
| 4035 // NOTE: If the left hand side produces a materialized value (not in | 4044 // NOTE: If the left hand side produces a materialized value (not in |
| 4036 // the CC register), we force the right hand side to do the | 4045 // the CC register), we force the right hand side to do the |
| 4037 // same. This is necessary because we may have to branch to the exit | 4046 // same. This is necessary because we may have to branch to the exit |
| 4038 // after evaluating the left hand side (due to the shortcut | 4047 // after evaluating the left hand side (due to the shortcut |
| 4039 // semantics), but the compiler must (statically) know if the result | 4048 // semantics), but the compiler must (statically) know if the result |
| 4040 // of compiling the binary operation is materialized or not. | 4049 // of compiling the binary operation is materialized or not. |
| 4041 | 4050 |
| 4042 if (op == Token::AND) { | 4051 if (op == Token::AND) { |
| 4043 JumpTarget is_true(this); | 4052 JumpTarget is_true(this); |
| 4044 LoadConditionAndSpill(node->left(), NOT_INSIDE_TYPEOF, | 4053 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, |
| 4045 &is_true, false_target(), false); | 4054 &is_true, false_target(), false); |
| 4046 if (has_cc() || frame_ == NULL) { | 4055 if (has_cc() || frame_ == NULL) { |
| 4047 if (has_cc()) { | 4056 if (has_cc()) { |
| 4048 ASSERT(has_valid_frame()); | 4057 ASSERT(has_valid_frame()); |
| 4049 Branch(false, false_target()); | 4058 Branch(false, false_target()); |
| 4050 } | 4059 } |
| 4051 | 4060 |
| 4052 if (has_valid_frame() || is_true.is_linked()) { | 4061 if (is_true.is_linked()) { |
| 4062 is_true.Bind(); |
| 4063 } |
| 4064 if (has_valid_frame()) { |
| 4053 // Evaluate right side expression. | 4065 // Evaluate right side expression. |
| 4054 is_true.Bind(); | 4066 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, |
| 4055 LoadConditionAndSpill(node->right(), NOT_INSIDE_TYPEOF, | 4067 true_target(), false_target(), false); |
| 4056 true_target(), false_target(), false); | |
| 4057 } | 4068 } |
| 4058 } else { | 4069 } else { |
| 4059 // We have a materialized value on the frame. | 4070 // We have a materialized value on the frame. |
| 4060 JumpTarget pop_and_continue(this); | 4071 JumpTarget pop_and_continue(this); |
| 4061 JumpTarget exit(this); | 4072 JumpTarget exit(this); |
| 4062 | 4073 |
| 4063 // Avoid popping the result if it converts to 'false' using the | 4074 // Avoid popping the result if it converts to 'false' using the |
| 4064 // standard ToBoolean() conversion as described in ECMA-262, section | 4075 // standard ToBoolean() conversion as described in ECMA-262, section |
| 4065 // 9.2, page 30. | 4076 // 9.2, page 30. |
| 4066 // | 4077 // |
| 4067 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 4078 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 4068 __ mov(eax, frame_->Top()); | 4079 frame_->Dup(); |
| 4069 frame_->EmitPush(eax); | |
| 4070 ToBoolean(&pop_and_continue, &exit); | 4080 ToBoolean(&pop_and_continue, &exit); |
| 4071 Branch(false, &exit); | 4081 Branch(false, &exit); |
| 4072 | 4082 |
| 4073 // Pop the result of evaluating the first part. | 4083 // Pop the result of evaluating the first part. |
| 4074 pop_and_continue.Bind(); | 4084 pop_and_continue.Bind(); |
| 4075 frame_->Drop(); | 4085 frame_->Drop(); |
| 4076 | 4086 |
| 4077 // Evaluate right side expression. | 4087 // Evaluate right side expression. |
| 4078 is_true.Bind(); | 4088 is_true.Bind(); |
| 4079 LoadAndSpill(node->right()); | 4089 Load(node->right()); |
| 4080 | 4090 |
| 4081 // Exit (always with a materialized value). | 4091 // Exit (always with a materialized value). |
| 4082 exit.Bind(); | 4092 exit.Bind(); |
| 4083 } | 4093 } |
| 4084 | 4094 |
| 4085 } else if (op == Token::OR) { | 4095 } else if (op == Token::OR) { |
| 4086 JumpTarget is_false(this); | 4096 JumpTarget is_false(this); |
| 4087 LoadConditionAndSpill(node->left(), NOT_INSIDE_TYPEOF, | 4097 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, |
| 4088 true_target(), &is_false, false); | 4098 true_target(), &is_false, false); |
| 4089 if (has_cc() || frame_ == NULL) { | 4099 if (has_cc() || frame_ == NULL) { |
| 4090 if (has_cc()) { | 4100 if (has_cc()) { |
| 4091 ASSERT(has_valid_frame()); | 4101 ASSERT(has_valid_frame()); |
| 4092 Branch(true, true_target()); | 4102 Branch(true, true_target()); |
| 4093 } | 4103 } |
| 4094 | 4104 |
| 4095 if (has_valid_frame() || is_false.is_linked()) { | 4105 if (is_false.is_linked()) { |
| 4096 // Evaluate right side expression. | 4106 // Evaluate right side expression. |
| 4097 is_false.Bind(); | 4107 is_false.Bind(); |
| 4098 LoadConditionAndSpill(node->right(), NOT_INSIDE_TYPEOF, | |
| 4099 true_target(), false_target(), false); | |
| 4100 } | 4108 } |
| 4101 | 4109 if (has_valid_frame()) { |
| 4110 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, |
| 4111 true_target(), false_target(), false); |
| 4112 } |
| 4102 } else { | 4113 } else { |
| 4103 // We have a materialized value on the frame. | 4114 // We have a materialized value on the frame. |
| 4104 JumpTarget pop_and_continue(this); | 4115 JumpTarget pop_and_continue(this); |
| 4105 JumpTarget exit(this); | 4116 JumpTarget exit(this); |
| 4106 | 4117 |
| 4107 // Avoid popping the result if it converts to 'true' using the | 4118 // Avoid popping the result if it converts to 'true' using the |
| 4108 // standard ToBoolean() conversion as described in ECMA-262, | 4119 // standard ToBoolean() conversion as described in ECMA-262, |
| 4109 // section 9.2, page 30. | 4120 // section 9.2, page 30. |
| 4110 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 4121 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 4111 __ mov(eax, frame_->Top()); | 4122 frame_->Dup(); |
| 4112 frame_->EmitPush(eax); | |
| 4113 ToBoolean(&exit, &pop_and_continue); | 4123 ToBoolean(&exit, &pop_and_continue); |
| 4114 Branch(true, &exit); | 4124 Branch(true, &exit); |
| 4115 | 4125 |
| 4116 // Pop the result of evaluating the first part. | 4126 // Pop the result of evaluating the first part. |
| 4117 pop_and_continue.Bind(); | 4127 pop_and_continue.Bind(); |
| 4118 frame_->Drop(); | 4128 frame_->Drop(); |
| 4119 | 4129 |
| 4120 // Evaluate right side expression. | 4130 // Evaluate right side expression. |
| 4121 is_false.Bind(); | 4131 is_false.Bind(); |
| 4122 LoadAndSpill(node->right()); | 4132 Load(node->right()); |
| 4123 | 4133 |
| 4124 // Exit (always with a materialized value). | 4134 // Exit (always with a materialized value). |
| 4125 exit.Bind(); | 4135 exit.Bind(); |
| 4126 } | 4136 } |
| 4127 | 4137 |
| 4128 } else { | 4138 } else { |
| 4139 VirtualFrame::SpilledScope spilled_scope(this); |
| 4129 // NOTE: The code below assumes that the slow cases (calls to runtime) | 4140 // NOTE: The code below assumes that the slow cases (calls to runtime) |
| 4130 // never return a constant/immutable object. | 4141 // never return a constant/immutable object. |
| 4131 OverwriteMode overwrite_mode = NO_OVERWRITE; | 4142 OverwriteMode overwrite_mode = NO_OVERWRITE; |
| 4132 if (node->left()->AsBinaryOperation() != NULL && | 4143 if (node->left()->AsBinaryOperation() != NULL && |
| 4133 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 4144 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
| 4134 overwrite_mode = OVERWRITE_LEFT; | 4145 overwrite_mode = OVERWRITE_LEFT; |
| 4135 } else if (node->right()->AsBinaryOperation() != NULL && | 4146 } else if (node->right()->AsBinaryOperation() != NULL && |
| 4136 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 4147 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
| 4137 overwrite_mode = OVERWRITE_RIGHT; | 4148 overwrite_mode = OVERWRITE_RIGHT; |
| 4138 } | 4149 } |
| (...skipping 1881 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6020 | 6031 |
| 6021 // Slow-case: Go through the JavaScript implementation. | 6032 // Slow-case: Go through the JavaScript implementation. |
| 6022 __ bind(&slow); | 6033 __ bind(&slow); |
| 6023 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6034 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6024 } | 6035 } |
| 6025 | 6036 |
| 6026 | 6037 |
| 6027 #undef __ | 6038 #undef __ |
| 6028 | 6039 |
| 6029 } } // namespace v8::internal | 6040 } } // namespace v8::internal |
| OLD | NEW |