Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 4550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4561 Drop(argument_count); | 4561 Drop(argument_count); |
| 4562 ast_context()->ReturnInstruction(call, expr->id()); | 4562 ast_context()->ReturnInstruction(call, expr->id()); |
| 4563 } | 4563 } |
| 4564 } | 4564 } |
| 4565 | 4565 |
| 4566 | 4566 |
| 4567 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { | 4567 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 4568 ASSERT(!HasStackOverflow()); | 4568 ASSERT(!HasStackOverflow()); |
| 4569 ASSERT(current_block() != NULL); | 4569 ASSERT(current_block() != NULL); |
| 4570 ASSERT(current_block()->HasPredecessor()); | 4570 ASSERT(current_block()->HasPredecessor()); |
| 4571 Token::Value op = expr->op(); | 4571 switch (expr->op()) { |
| 4572 if (op == Token::VOID) { | 4572 case Token::DELETE: return VisitDelete(expr); |
| 4573 case Token::VOID: return VisitVoid(expr); | |
| 4574 case Token::TYPEOF: return VisitTypeof(expr); | |
| 4575 case Token::ADD: return VisitAdd(expr); | |
| 4576 case Token::SUB: return VisitSub(expr); | |
| 4577 case Token::BIT_NOT: return VisitBitNot(expr); | |
| 4578 case Token::NOT: return VisitNot(expr); | |
| 4579 default: UNREACHABLE(); | |
| 4580 } | |
| 4581 } | |
| 4582 | |
| 4583 void HGraphBuilder::VisitDelete(UnaryOperation* expr) { | |
| 4584 Property* prop = expr->expression()->AsProperty(); | |
| 4585 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | |
| 4586 if (prop == NULL && var == NULL) { | |
| 4587 // Result of deleting non-property, non-variable reference is true. | |
| 4588 // Evaluate the subexpression for side effects. | |
| 4573 CHECK_ALIVE(VisitForEffect(expr->expression())); | 4589 CHECK_ALIVE(VisitForEffect(expr->expression())); |
| 4574 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 4590 ast_context()->ReturnValue(graph()->GetConstantTrue()); |
| 4575 } else if (op == Token::DELETE) { | 4591 } else if (var != NULL && |
| 4576 Property* prop = expr->expression()->AsProperty(); | 4592 !var->is_global() && |
| 4577 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4593 var->AsSlot() != NULL && |
| 4578 if (prop == NULL && var == NULL) { | 4594 var->AsSlot()->type() != Slot::LOOKUP) { |
| 4579 // Result of deleting non-property, non-variable reference is true. | 4595 // Result of deleting non-global, non-dynamic variables is false. |
| 4580 // Evaluate the subexpression for side effects. | 4596 // The subexpression does not have side effects. |
| 4581 CHECK_ALIVE(VisitForEffect(expr->expression())); | 4597 ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4582 ast_context()->ReturnValue(graph()->GetConstantTrue()); | 4598 } else if (prop != NULL) { |
| 4583 } else if (var != NULL && | 4599 if (prop->is_synthetic()) { |
| 4584 !var->is_global() && | 4600 // Result of deleting parameters is false, even when they rewrite |
| 4585 var->AsSlot() != NULL && | 4601 // to accesses on the arguments object. |
| 4586 var->AsSlot()->type() != Slot::LOOKUP) { | |
| 4587 // Result of deleting non-global, non-dynamic variables is false. | |
| 4588 // The subexpression does not have side effects. | |
| 4589 ast_context()->ReturnValue(graph()->GetConstantFalse()); | 4602 ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4590 } else if (prop != NULL) { | |
| 4591 if (prop->is_synthetic()) { | |
| 4592 // Result of deleting parameters is false, even when they rewrite | |
| 4593 // to accesses on the arguments object. | |
| 4594 ast_context()->ReturnValue(graph()->GetConstantFalse()); | |
| 4595 } else { | |
| 4596 CHECK_ALIVE(VisitForValue(prop->obj())); | |
| 4597 CHECK_ALIVE(VisitForValue(prop->key())); | |
| 4598 HValue* key = Pop(); | |
| 4599 HValue* obj = Pop(); | |
| 4600 HDeleteProperty* instr = new(zone()) HDeleteProperty(obj, key); | |
| 4601 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4602 } | |
| 4603 } else if (var->is_global()) { | |
| 4604 return Bailout("delete with global variable"); | |
| 4605 } else { | 4603 } else { |
| 4606 return Bailout("delete with non-global variable"); | 4604 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 4605 CHECK_ALIVE(VisitForValue(prop->key())); | |
| 4606 HValue* key = Pop(); | |
| 4607 HValue* obj = Pop(); | |
| 4608 HDeleteProperty* instr = new(zone()) HDeleteProperty(obj, key); | |
| 4609 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4607 } | 4610 } |
| 4608 } else if (op == Token::NOT) { | 4611 } else if (var->is_global()) { |
| 4609 if (ast_context()->IsTest()) { | 4612 Bailout("delete with global variable"); |
| 4610 TestContext* context = TestContext::cast(ast_context()); | |
| 4611 VisitForControl(expr->expression(), | |
| 4612 context->if_false(), | |
| 4613 context->if_true()); | |
| 4614 } else if (ast_context()->IsValue()) { | |
| 4615 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); | |
| 4616 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); | |
| 4617 CHECK_BAILOUT(VisitForControl(expr->expression(), | |
| 4618 materialize_false, | |
| 4619 materialize_true)); | |
| 4620 | |
| 4621 if (materialize_false->HasPredecessor()) { | |
| 4622 materialize_false->SetJoinId(expr->expression()->id()); | |
| 4623 set_current_block(materialize_false); | |
| 4624 Push(graph()->GetConstantFalse()); | |
| 4625 } else { | |
| 4626 materialize_false = NULL; | |
| 4627 } | |
| 4628 | |
| 4629 if (materialize_true->HasPredecessor()) { | |
| 4630 materialize_true->SetJoinId(expr->expression()->id()); | |
| 4631 set_current_block(materialize_true); | |
| 4632 Push(graph()->GetConstantTrue()); | |
| 4633 } else { | |
| 4634 materialize_true = NULL; | |
| 4635 } | |
| 4636 | |
| 4637 HBasicBlock* join = | |
| 4638 CreateJoin(materialize_false, materialize_true, expr->id()); | |
| 4639 set_current_block(join); | |
| 4640 if (join != NULL) ast_context()->ReturnValue(Pop()); | |
| 4641 } else { | |
| 4642 ASSERT(ast_context()->IsEffect()); | |
| 4643 VisitForEffect(expr->expression()); | |
| 4644 } | |
| 4645 | |
| 4646 } else if (op == Token::TYPEOF) { | |
| 4647 CHECK_ALIVE(VisitForTypeOf(expr->expression())); | |
| 4648 HValue* value = Pop(); | |
| 4649 ast_context()->ReturnInstruction(new(zone()) HTypeof(value), expr->id()); | |
| 4650 | |
| 4651 } else { | 4613 } else { |
| 4652 CHECK_ALIVE(VisitForValue(expr->expression())); | 4614 Bailout("delete with non-global variable"); |
| 4653 HValue* value = Pop(); | |
| 4654 HInstruction* instr = NULL; | |
| 4655 switch (op) { | |
| 4656 case Token::BIT_NOT: | |
| 4657 instr = new(zone()) HBitNot(value); | |
| 4658 break; | |
| 4659 case Token::SUB: | |
| 4660 instr = new(zone()) HMul(value, graph_->GetConstantMinus1()); | |
| 4661 break; | |
| 4662 case Token::ADD: | |
| 4663 instr = new(zone()) HMul(value, graph_->GetConstant1()); | |
| 4664 break; | |
| 4665 default: | |
| 4666 return Bailout("Value: unsupported unary operation"); | |
| 4667 break; | |
| 4668 } | |
| 4669 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4670 } | 4615 } |
| 4671 } | 4616 } |
| 4672 | 4617 |
| 4673 | 4618 |
| 4619 void HGraphBuilder::VisitVoid(UnaryOperation* expr) { | |
| 4620 CHECK_ALIVE(VisitForEffect(expr->expression())); | |
| 4621 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | |
| 4622 } | |
| 4623 | |
| 4624 | |
| 4625 void HGraphBuilder::VisitTypeof(UnaryOperation* expr) { | |
| 4626 CHECK_ALIVE(VisitForTypeOf(expr->expression())); | |
| 4627 HValue* value = Pop(); | |
| 4628 ast_context()->ReturnInstruction(new(zone()) HTypeof(value), expr->id()); | |
| 4629 } | |
| 4630 | |
| 4631 | |
| 4632 void HGraphBuilder::VisitAdd(UnaryOperation* expr) { | |
| 4633 CHECK_ALIVE(VisitForValue(expr->expression())); | |
| 4634 HValue* value = Pop(); | |
| 4635 HInstruction* instr = new(zone()) HMul(value, graph_->GetConstant1()); | |
| 4636 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4637 } | |
| 4638 | |
| 4639 | |
| 4640 void HGraphBuilder::VisitSub(UnaryOperation* expr) { | |
| 4641 CHECK_ALIVE(VisitForValue(expr->expression())); | |
| 4642 HValue* value = Pop(); | |
| 4643 HInstruction* instr = new(zone()) HMul(value, graph_->GetConstantMinus1()); | |
| 4644 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4645 } | |
| 4646 | |
| 4647 | |
| 4648 void HGraphBuilder::VisitBitNot(UnaryOperation* expr) { | |
| 4649 CHECK_ALIVE(VisitForValue(expr->expression())); | |
| 4650 HValue* value = Pop(); | |
| 4651 HInstruction* instr = new(zone()) HBitNot(value); | |
| 4652 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4653 } | |
| 4654 | |
| 4655 | |
| 4656 void HGraphBuilder::VisitNot(UnaryOperation* expr) { | |
| 4657 // TODO(svenpanne) Perhaps a switch/virtual function is nicer here. | |
| 4658 if (ast_context()->IsTest()) { | |
| 4659 TestContext* context = TestContext::cast(ast_context()); | |
| 4660 VisitForControl(expr->expression(), | |
| 4661 context->if_false(), | |
| 4662 context->if_true()); | |
| 4663 return; | |
| 4664 } | |
| 4665 | |
| 4666 if (ast_context()->IsEffect()) { | |
| 4667 VisitForEffect(expr->expression()); | |
| 4668 return; | |
| 4669 } | |
| 4670 | |
| 4671 ASSERT(ast_context()->IsValue()); | |
| 4672 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); | |
| 4673 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); | |
| 4674 CHECK_BAILOUT(VisitForControl(expr->expression(), | |
| 4675 materialize_false, | |
| 4676 materialize_true)); | |
| 4677 | |
| 4678 if (materialize_false->HasPredecessor()) { | |
| 4679 materialize_false->SetJoinId(expr->expression()->id()); | |
| 4680 set_current_block(materialize_false); | |
| 4681 Push(graph()->GetConstantFalse()); | |
| 4682 } else { | |
| 4683 materialize_false = NULL; | |
| 4684 } | |
| 4685 | |
| 4686 if (materialize_true->HasPredecessor()) { | |
| 4687 materialize_true->SetJoinId(expr->expression()->id()); | |
| 4688 set_current_block(materialize_true); | |
| 4689 Push(graph()->GetConstantTrue()); | |
| 4690 } else { | |
| 4691 materialize_true = NULL; | |
| 4692 } | |
| 4693 | |
| 4694 HBasicBlock* join = | |
| 4695 CreateJoin(materialize_false, materialize_true, expr->id()); | |
| 4696 set_current_block(join); | |
| 4697 if (join != NULL) ast_context()->ReturnValue(Pop()); | |
| 4698 } | |
| 4699 | |
| 4700 | |
| 4674 HInstruction* HGraphBuilder::BuildIncrement(HValue* value, | 4701 HInstruction* HGraphBuilder::BuildIncrement(HValue* value, |
| 4675 bool increment, | 4702 bool increment, |
| 4676 CountOperation* expr) { | 4703 CountOperation* expr) { |
| 4677 HConstant* delta = increment | 4704 HConstant* delta = increment |
| 4678 ? graph_->GetConstant1() | 4705 ? graph_->GetConstant1() |
| 4679 : graph_->GetConstantMinus1(); | 4706 : graph_->GetConstantMinus1(); |
| 4680 HInstruction* instr = new(zone()) HAdd(value, delta); | 4707 HInstruction* instr = new(zone()) HAdd(value, delta); |
| 4681 Representation rep = ToRepresentation(oracle()->IncrementType(expr)); | 4708 Representation rep = ToRepresentation(oracle()->IncrementType(expr)); |
| 4682 if (rep.IsTagged()) { | 4709 if (rep.IsTagged()) { |
| 4683 rep = Representation::Integer32(); | 4710 rep = Representation::Integer32(); |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4827 AddInstruction(length); | 4854 AddInstruction(length); |
| 4828 AddInstruction(new(zone()) HBoundsCheck(index, length)); | 4855 AddInstruction(new(zone()) HBoundsCheck(index, length)); |
| 4829 return new(zone()) HStringCharCodeAt(string, index); | 4856 return new(zone()) HStringCharCodeAt(string, index); |
| 4830 } | 4857 } |
| 4831 | 4858 |
| 4832 | 4859 |
| 4833 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, | 4860 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
| 4834 HValue* left, | 4861 HValue* left, |
| 4835 HValue* right) { | 4862 HValue* right) { |
| 4836 TypeInfo info = oracle()->BinaryType(expr); | 4863 TypeInfo info = oracle()->BinaryType(expr); |
| 4837 HInstruction* instr = NULL; | 4864 HInstruction* instr = BuildBinaryOperation(expr->op(), left, right, info); |
|
fschneider
2011/05/10 13:34:20
I agree with Kevin to a degree.
Having two functi
| |
| 4838 switch (expr->op()) { | |
| 4839 case Token::ADD: | |
| 4840 if (info.IsString()) { | |
| 4841 AddInstruction(new(zone()) HCheckNonSmi(left)); | |
| 4842 AddInstruction(new(zone()) HCheckInstanceType( | |
| 4843 left, FIRST_STRING_TYPE, LAST_STRING_TYPE)); | |
| 4844 AddInstruction(new(zone()) HCheckNonSmi(right)); | |
| 4845 AddInstruction(new(zone()) HCheckInstanceType( | |
| 4846 right, FIRST_STRING_TYPE, LAST_STRING_TYPE)); | |
| 4847 instr = new(zone()) HStringAdd(left, right); | |
| 4848 } else { | |
| 4849 instr = new(zone()) HAdd(left, right); | |
| 4850 } | |
| 4851 break; | |
| 4852 case Token::SUB: | |
| 4853 instr = new(zone()) HSub(left, right); | |
| 4854 break; | |
| 4855 case Token::MUL: | |
| 4856 instr = new(zone()) HMul(left, right); | |
| 4857 break; | |
| 4858 case Token::MOD: | |
| 4859 instr = new(zone()) HMod(left, right); | |
| 4860 break; | |
| 4861 case Token::DIV: | |
| 4862 instr = new(zone()) HDiv(left, right); | |
| 4863 break; | |
| 4864 case Token::BIT_XOR: | |
| 4865 instr = new(zone()) HBitXor(left, right); | |
| 4866 break; | |
| 4867 case Token::BIT_AND: | |
| 4868 instr = new(zone()) HBitAnd(left, right); | |
| 4869 break; | |
| 4870 case Token::BIT_OR: | |
| 4871 instr = new(zone()) HBitOr(left, right); | |
| 4872 break; | |
| 4873 case Token::SAR: | |
| 4874 instr = new(zone()) HSar(left, right); | |
| 4875 break; | |
| 4876 case Token::SHR: | |
| 4877 instr = new(zone()) HShr(left, right); | |
| 4878 break; | |
| 4879 case Token::SHL: | |
| 4880 instr = new(zone()) HShl(left, right); | |
| 4881 break; | |
| 4882 default: | |
| 4883 UNREACHABLE(); | |
| 4884 } | |
| 4885 // If we hit an uninitialized binary op stub we will get type info | 4865 // If we hit an uninitialized binary op stub we will get type info |
| 4886 // for a smi operation. If one of the operands is a constant string | 4866 // for a smi operation. If one of the operands is a constant string |
| 4887 // do not generate code assuming it is a smi operation. | 4867 // do not generate code assuming it is a smi operation. |
| 4888 if (info.IsSmi() && | 4868 if (info.IsSmi() && |
| 4889 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || | 4869 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || |
| 4890 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { | 4870 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { |
| 4891 return instr; | 4871 return instr; |
| 4892 } | 4872 } |
| 4893 if (FLAG_trace_representation) { | 4873 if (FLAG_trace_representation) { |
| 4894 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic()); | 4874 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic()); |
| 4895 } | 4875 } |
| 4896 Representation rep = ToRepresentation(info); | 4876 Representation rep = ToRepresentation(info); |
| 4897 // We only generate either int32 or generic tagged bitwise operations. | 4877 // We only generate either int32 or generic tagged bitwise operations. |
| 4898 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { | 4878 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { |
| 4899 rep = Representation::Integer32(); | 4879 rep = Representation::Integer32(); |
| 4900 } | 4880 } |
| 4901 AssumeRepresentation(instr, rep); | 4881 AssumeRepresentation(instr, rep); |
| 4902 return instr; | 4882 return instr; |
| 4903 } | 4883 } |
| 4904 | 4884 |
| 4905 | 4885 |
| 4886 HInstruction* HGraphBuilder::BuildBinaryOperation( | |
| 4887 Token::Value op, HValue* left, HValue* right, TypeInfo info) { | |
| 4888 switch (op) { | |
| 4889 case Token::ADD: | |
| 4890 if (info.IsString()) { | |
| 4891 AddInstruction(new(zone()) HCheckNonSmi(left)); | |
| 4892 AddInstruction(new(zone()) HCheckInstanceType(left, FIRST_STRING_TYPE, | |
| 4893 LAST_STRING_TYPE)); | |
| 4894 AddInstruction(new(zone()) HCheckNonSmi(right)); | |
| 4895 AddInstruction(new(zone()) HCheckInstanceType(right, FIRST_STRING_TYPE, | |
| 4896 LAST_STRING_TYPE)); | |
| 4897 return new(zone()) HStringAdd(left, right); | |
| 4898 } else { | |
| 4899 return new(zone()) HAdd(left, right); | |
| 4900 } | |
| 4901 case Token::SUB: return new(zone()) HSub(left, right); | |
| 4902 case Token::MUL: return new(zone()) HMul(left, right); | |
| 4903 case Token::MOD: return new(zone()) HMod(left, right); | |
| 4904 case Token::DIV: return new(zone()) HDiv(left, right); | |
| 4905 case Token::BIT_XOR: return new(zone()) HBitXor(left, right); | |
| 4906 case Token::BIT_AND: return new(zone()) HBitAnd(left, right); | |
| 4907 case Token::BIT_OR: return new(zone()) HBitOr(left, right); | |
| 4908 case Token::SAR: return new(zone()) HSar(left, right); | |
| 4909 case Token::SHR: return new(zone()) HShr(left, right); | |
| 4910 case Token::SHL: return new(zone()) HShl(left, right); | |
| 4911 default: | |
| 4912 UNREACHABLE(); | |
| 4913 return NULL; | |
| 4914 } | |
| 4915 } | |
| 4916 | |
| 4917 | |
| 4906 // Check for the form (%_ClassOf(foo) === 'BarClass'). | 4918 // Check for the form (%_ClassOf(foo) === 'BarClass'). |
| 4907 static bool IsClassOfTest(CompareOperation* expr) { | 4919 static bool IsClassOfTest(CompareOperation* expr) { |
| 4908 if (expr->op() != Token::EQ_STRICT) return false; | 4920 if (expr->op() != Token::EQ_STRICT) return false; |
| 4909 CallRuntime* call = expr->left()->AsCallRuntime(); | 4921 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 4910 if (call == NULL) return false; | 4922 if (call == NULL) return false; |
| 4911 Literal* literal = expr->right()->AsLiteral(); | 4923 Literal* literal = expr->right()->AsLiteral(); |
| 4912 if (literal == NULL) return false; | 4924 if (literal == NULL) return false; |
| 4913 if (!literal->handle()->IsString()) return false; | 4925 if (!literal->handle()->IsString()) return false; |
| 4914 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; | 4926 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; |
| 4915 ASSERT(call->arguments()->length() == 1); | 4927 ASSERT(call->arguments()->length() == 1); |
| 4916 return true; | 4928 return true; |
| 4917 } | 4929 } |
| 4918 | 4930 |
| 4919 | 4931 |
| 4920 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { | 4932 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
| 4921 ASSERT(!HasStackOverflow()); | 4933 ASSERT(!HasStackOverflow()); |
| 4922 ASSERT(current_block() != NULL); | 4934 ASSERT(current_block() != NULL); |
| 4923 ASSERT(current_block()->HasPredecessor()); | 4935 ASSERT(current_block()->HasPredecessor()); |
| 4924 if (expr->op() == Token::COMMA) { | 4936 switch (expr->op()) { |
| 4925 CHECK_ALIVE(VisitForEffect(expr->left())); | 4937 case Token::COMMA: return VisitComma(expr); |
| 4926 // Visit the right subexpression in the same AST context as the entire | 4938 case Token::OR: return VisitAndOr(expr, false); |
| 4927 // expression. | 4939 case Token::AND: return VisitAndOr(expr, true); |
| 4928 Visit(expr->right()); | 4940 default: return VisitCommon(expr); |
| 4941 } | |
| 4942 } | |
| 4929 | 4943 |
| 4930 } else if (expr->op() == Token::AND || expr->op() == Token::OR) { | |
| 4931 bool is_logical_and = (expr->op() == Token::AND); | |
| 4932 if (ast_context()->IsTest()) { | |
| 4933 TestContext* context = TestContext::cast(ast_context()); | |
| 4934 // Translate left subexpression. | |
| 4935 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | |
| 4936 if (is_logical_and) { | |
| 4937 CHECK_BAILOUT(VisitForControl(expr->left(), | |
| 4938 eval_right, | |
| 4939 context->if_false())); | |
| 4940 } else { | |
| 4941 CHECK_BAILOUT(VisitForControl(expr->left(), | |
| 4942 context->if_true(), | |
| 4943 eval_right)); | |
| 4944 } | |
| 4945 | 4944 |
| 4946 // Translate right subexpression by visiting it in the same AST | 4945 void HGraphBuilder::VisitComma(BinaryOperation* expr) { |
| 4947 // context as the entire expression. | 4946 CHECK_ALIVE(VisitForEffect(expr->left())); |
| 4948 if (eval_right->HasPredecessor()) { | 4947 // Visit the right subexpression in the same AST context as the entire |
| 4949 eval_right->SetJoinId(expr->RightId()); | 4948 // expression. |
| 4950 set_current_block(eval_right); | 4949 Visit(expr->right()); |
| 4951 Visit(expr->right()); | 4950 } |
| 4952 } | |
| 4953 | 4951 |
| 4954 } else if (ast_context()->IsValue()) { | |
| 4955 CHECK_ALIVE(VisitForValue(expr->left())); | |
| 4956 ASSERT(current_block() != NULL); | |
| 4957 | 4952 |
| 4958 // We need an extra block to maintain edge-split form. | 4953 void HGraphBuilder::VisitAndOr(BinaryOperation* expr, bool is_logical_and) { |
| 4959 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | 4954 if (ast_context()->IsTest()) { |
| 4960 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | 4955 TestContext* context = TestContext::cast(ast_context()); |
| 4961 HTest* test = is_logical_and | 4956 // Translate left subexpression. |
| 4962 ? new(zone()) HTest(Top(), eval_right, empty_block) | 4957 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 4963 : new(zone()) HTest(Top(), empty_block, eval_right); | 4958 if (is_logical_and) { |
| 4964 current_block()->Finish(test); | 4959 CHECK_BAILOUT(VisitForControl(expr->left(), |
| 4965 | 4960 eval_right, |
| 4966 set_current_block(eval_right); | 4961 context->if_false())); |
| 4967 Drop(1); // Value of the left subexpression. | |
| 4968 CHECK_BAILOUT(VisitForValue(expr->right())); | |
| 4969 | |
| 4970 HBasicBlock* join_block = | |
| 4971 CreateJoin(empty_block, current_block(), expr->id()); | |
| 4972 set_current_block(join_block); | |
| 4973 ast_context()->ReturnValue(Pop()); | |
| 4974 | |
| 4975 } else { | 4962 } else { |
| 4976 ASSERT(ast_context()->IsEffect()); | 4963 CHECK_BAILOUT(VisitForControl(expr->left(), |
| 4977 // In an effect context, we don't need the value of the left | 4964 context->if_true(), |
| 4978 // subexpression, only its control flow and side effects. We need an | 4965 eval_right)); |
| 4979 // extra block to maintain edge-split form. | |
| 4980 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | |
| 4981 HBasicBlock* right_block = graph()->CreateBasicBlock(); | |
| 4982 if (is_logical_and) { | |
| 4983 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block)); | |
| 4984 } else { | |
| 4985 CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block)); | |
| 4986 } | |
| 4987 | |
| 4988 // TODO(kmillikin): Find a way to fix this. It's ugly that there are | |
| 4989 // actually two empty blocks (one here and one inserted by | |
| 4990 // TestContext::BuildBranch, and that they both have an HSimulate | |
| 4991 // though the second one is not a merge node, and that we really have | |
| 4992 // no good AST ID to put on that first HSimulate. | |
| 4993 if (empty_block->HasPredecessor()) { | |
| 4994 empty_block->SetJoinId(expr->id()); | |
| 4995 } else { | |
| 4996 empty_block = NULL; | |
| 4997 } | |
| 4998 | |
| 4999 if (right_block->HasPredecessor()) { | |
| 5000 right_block->SetJoinId(expr->RightId()); | |
| 5001 set_current_block(right_block); | |
| 5002 CHECK_BAILOUT(VisitForEffect(expr->right())); | |
| 5003 right_block = current_block(); | |
| 5004 } else { | |
| 5005 right_block = NULL; | |
| 5006 } | |
| 5007 | |
| 5008 HBasicBlock* join_block = | |
| 5009 CreateJoin(empty_block, right_block, expr->id()); | |
| 5010 set_current_block(join_block); | |
| 5011 // We did not materialize any value in the predecessor environments, | |
| 5012 // so there is no need to handle it here. | |
| 5013 } | 4966 } |
| 5014 | 4967 |
| 4968 // Translate right subexpression by visiting it in the same AST | |
| 4969 // context as the entire expression. | |
| 4970 if (eval_right->HasPredecessor()) { | |
| 4971 eval_right->SetJoinId(expr->RightId()); | |
| 4972 set_current_block(eval_right); | |
| 4973 Visit(expr->right()); | |
| 4974 } | |
| 4975 | |
| 4976 } else if (ast_context()->IsValue()) { | |
| 4977 CHECK_ALIVE(VisitForValue(expr->left())); | |
| 4978 ASSERT(current_block() != NULL); | |
| 4979 | |
| 4980 // We need an extra block to maintain edge-split form. | |
| 4981 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | |
| 4982 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | |
| 4983 HTest* test = is_logical_and | |
| 4984 ? new(zone()) HTest(Top(), eval_right, empty_block) | |
| 4985 : new(zone()) HTest(Top(), empty_block, eval_right); | |
| 4986 current_block()->Finish(test); | |
| 4987 | |
| 4988 set_current_block(eval_right); | |
| 4989 Drop(1); // Value of the left subexpression. | |
| 4990 CHECK_BAILOUT(VisitForValue(expr->right())); | |
| 4991 | |
| 4992 HBasicBlock* join_block = | |
| 4993 CreateJoin(empty_block, current_block(), expr->id()); | |
| 4994 set_current_block(join_block); | |
| 4995 ast_context()->ReturnValue(Pop()); | |
| 4996 | |
| 5015 } else { | 4997 } else { |
| 5016 CHECK_ALIVE(VisitForValue(expr->left())); | 4998 ASSERT(ast_context()->IsEffect()); |
| 5017 CHECK_ALIVE(VisitForValue(expr->right())); | 4999 // In an effect context, we don't need the value of the left subexpression, |
| 5000 // only its control flow and side effects. We need an extra block to | |
| 5001 // maintain edge-split form. | |
| 5002 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | |
| 5003 HBasicBlock* right_block = graph()->CreateBasicBlock(); | |
| 5004 if (is_logical_and) { | |
| 5005 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block)); | |
| 5006 } else { | |
| 5007 CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block)); | |
| 5008 } | |
| 5018 | 5009 |
| 5019 HValue* right = Pop(); | 5010 // TODO(kmillikin): Find a way to fix this. It's ugly that there are |
| 5020 HValue* left = Pop(); | 5011 // actually two empty blocks (one here and one inserted by |
| 5021 HInstruction* instr = BuildBinaryOperation(expr, left, right); | 5012 // TestContext::BuildBranch, and that they both have an HSimulate though the |
| 5022 instr->set_position(expr->position()); | 5013 // second one is not a merge node, and that we really have no good AST ID to |
| 5023 ast_context()->ReturnInstruction(instr, expr->id()); | 5014 // put on that first HSimulate. |
| 5015 | |
| 5016 if (empty_block->HasPredecessor()) { | |
| 5017 empty_block->SetJoinId(expr->id()); | |
| 5018 } else { | |
| 5019 empty_block = NULL; | |
| 5020 } | |
| 5021 | |
| 5022 if (right_block->HasPredecessor()) { | |
| 5023 right_block->SetJoinId(expr->RightId()); | |
| 5024 set_current_block(right_block); | |
| 5025 CHECK_BAILOUT(VisitForEffect(expr->right())); | |
| 5026 right_block = current_block(); | |
| 5027 } else { | |
| 5028 right_block = NULL; | |
| 5029 } | |
| 5030 | |
| 5031 HBasicBlock* join_block = | |
| 5032 CreateJoin(empty_block, right_block, expr->id()); | |
| 5033 set_current_block(join_block); | |
| 5034 // We did not materialize any value in the predecessor environments, | |
| 5035 // so there is no need to handle it here. | |
| 5024 } | 5036 } |
| 5025 } | 5037 } |
| 5026 | 5038 |
| 5027 | 5039 |
| 5040 void HGraphBuilder::VisitCommon(BinaryOperation* expr) { | |
| 5041 CHECK_ALIVE(VisitForValue(expr->left())); | |
| 5042 CHECK_ALIVE(VisitForValue(expr->right())); | |
| 5043 HValue* right = Pop(); | |
| 5044 HValue* left = Pop(); | |
| 5045 HInstruction* instr = BuildBinaryOperation(expr, left, right); | |
| 5046 instr->set_position(expr->position()); | |
| 5047 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 5048 } | |
| 5049 | |
| 5050 | |
| 5028 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { | 5051 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { |
| 5029 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { | 5052 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { |
| 5030 if (FLAG_trace_representation) { | 5053 if (FLAG_trace_representation) { |
| 5031 PrintF("Assume representation for %s to be %s (%d)\n", | 5054 PrintF("Assume representation for %s to be %s (%d)\n", |
| 5032 value->Mnemonic(), | 5055 value->Mnemonic(), |
| 5033 r.Mnemonic(), | 5056 r.Mnemonic(), |
| 5034 graph_->GetMaximumValueID()); | 5057 graph_->GetMaximumValueID()); |
| 5035 } | 5058 } |
| 5036 value->ChangeRepresentation(r); | 5059 value->ChangeRepresentation(r); |
| 5037 // The representation of the value is dictated by type feedback and | 5060 // The representation of the value is dictated by type feedback and |
| (...skipping 1059 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6097 } | 6120 } |
| 6098 } | 6121 } |
| 6099 | 6122 |
| 6100 #ifdef DEBUG | 6123 #ifdef DEBUG |
| 6101 if (graph_ != NULL) graph_->Verify(); | 6124 if (graph_ != NULL) graph_->Verify(); |
| 6102 if (allocator_ != NULL) allocator_->Verify(); | 6125 if (allocator_ != NULL) allocator_->Verify(); |
| 6103 #endif | 6126 #endif |
| 6104 } | 6127 } |
| 6105 | 6128 |
| 6106 } } // namespace v8::internal | 6129 } } // namespace v8::internal |
| OLD | NEW |