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

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

Issue 17607: Computes Boolean AND and OR without spilling frames. (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 389 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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