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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 loop_information_(NULL), | 61 loop_information_(NULL), |
62 predecessors_(2), | 62 predecessors_(2), |
63 dominator_(NULL), | 63 dominator_(NULL), |
64 dominated_blocks_(4), | 64 dominated_blocks_(4), |
65 last_environment_(NULL), | 65 last_environment_(NULL), |
66 argument_count_(-1), | 66 argument_count_(-1), |
67 first_instruction_index_(-1), | 67 first_instruction_index_(-1), |
68 last_instruction_index_(-1), | 68 last_instruction_index_(-1), |
69 deleted_phis_(4), | 69 deleted_phis_(4), |
70 parent_loop_header_(NULL), | 70 parent_loop_header_(NULL), |
71 is_inline_return_target_(false) { | 71 is_inline_return_target_(false) { } |
72 } | |
73 | 72 |
74 | 73 |
75 void HBasicBlock::AttachLoopInformation() { | 74 void HBasicBlock::AttachLoopInformation() { |
76 ASSERT(!IsLoopHeader()); | 75 ASSERT(!IsLoopHeader()); |
77 loop_information_ = new(zone()) HLoopInformation(this); | 76 loop_information_ = new(zone()) HLoopInformation(this); |
78 } | 77 } |
79 | 78 |
80 | 79 |
81 void HBasicBlock::DetachLoopInformation() { | 80 void HBasicBlock::DetachLoopInformation() { |
82 ASSERT(IsLoopHeader()); | 81 ASSERT(IsLoopHeader()); |
(...skipping 4216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4299 | 4298 |
4300 empty_true->Goto(inlined_test_context()->if_true(), false); | 4299 empty_true->Goto(inlined_test_context()->if_true(), false); |
4301 empty_false->Goto(inlined_test_context()->if_false(), false); | 4300 empty_false->Goto(inlined_test_context()->if_false(), false); |
4302 } | 4301 } |
4303 } | 4302 } |
4304 | 4303 |
4305 // Fix up the function exits. | 4304 // Fix up the function exits. |
4306 if (inlined_test_context() != NULL) { | 4305 if (inlined_test_context() != NULL) { |
4307 HBasicBlock* if_true = inlined_test_context()->if_true(); | 4306 HBasicBlock* if_true = inlined_test_context()->if_true(); |
4308 HBasicBlock* if_false = inlined_test_context()->if_false(); | 4307 HBasicBlock* if_false = inlined_test_context()->if_false(); |
4309 if_true->SetJoinId(expr->id()); | 4308 |
4310 if_false->SetJoinId(expr->id()); | 4309 // Pop the return test context from the expression context stack. |
4311 ASSERT(ast_context() == inlined_test_context()); | 4310 ASSERT(ast_context() == inlined_test_context()); |
4312 // Pop the return test context from the expression context stack. | |
4313 ClearInlinedTestContext(); | 4311 ClearInlinedTestContext(); |
4314 | 4312 |
4315 // Forward to the real test context. | 4313 // Forward to the real test context. |
4316 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 4314 if (if_true->HasPredecessor()) { |
4317 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 4315 if_true->SetJoinId(expr->id()); |
4318 if_true->Goto(true_target, false); | 4316 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
4319 if_false->Goto(false_target, false); | 4317 if_true->Goto(true_target, false); |
4320 | 4318 } |
4321 // TODO(kmillikin): Come up with a better way to handle this. It is too | 4319 if (if_false->HasPredecessor()) { |
4322 // subtle. NULL here indicates that the enclosing context has no control | 4320 if_false->SetJoinId(expr->id()); |
4323 // flow to handle. | 4321 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
| 4322 if_false->Goto(false_target, false); |
| 4323 } |
4324 set_current_block(NULL); | 4324 set_current_block(NULL); |
4325 | 4325 |
4326 } else if (function_return()->HasPredecessor()) { | 4326 } else if (function_return()->HasPredecessor()) { |
4327 function_return()->SetJoinId(expr->id()); | 4327 function_return()->SetJoinId(expr->id()); |
4328 set_current_block(function_return()); | 4328 set_current_block(function_return()); |
4329 } else { | 4329 } else { |
4330 set_current_block(NULL); | 4330 set_current_block(NULL); |
4331 } | 4331 } |
4332 | 4332 |
4333 return true; | 4333 return true; |
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4780 HInstruction* instr = new(zone()) HMul(value, graph_->GetConstant1()); | 4780 HInstruction* instr = new(zone()) HMul(value, graph_->GetConstant1()); |
4781 ast_context()->ReturnInstruction(instr, expr->id()); | 4781 ast_context()->ReturnInstruction(instr, expr->id()); |
4782 } | 4782 } |
4783 | 4783 |
4784 | 4784 |
4785 void HGraphBuilder::VisitSub(UnaryOperation* expr) { | 4785 void HGraphBuilder::VisitSub(UnaryOperation* expr) { |
4786 CHECK_ALIVE(VisitForValue(expr->expression())); | 4786 CHECK_ALIVE(VisitForValue(expr->expression())); |
4787 HValue* value = Pop(); | 4787 HValue* value = Pop(); |
4788 HInstruction* instr = new(zone()) HMul(value, graph_->GetConstantMinus1()); | 4788 HInstruction* instr = new(zone()) HMul(value, graph_->GetConstantMinus1()); |
4789 TypeInfo info = oracle()->UnaryType(expr); | 4789 TypeInfo info = oracle()->UnaryType(expr); |
| 4790 if (info.IsUninitialized()) { |
| 4791 AddInstruction(new(zone()) HSoftDeoptimize); |
| 4792 info = TypeInfo::Unknown(); |
| 4793 } |
4790 Representation rep = ToRepresentation(info); | 4794 Representation rep = ToRepresentation(info); |
4791 TraceRepresentation(expr->op(), info, instr, rep); | 4795 TraceRepresentation(expr->op(), info, instr, rep); |
4792 instr->AssumeRepresentation(rep); | 4796 instr->AssumeRepresentation(rep); |
4793 ast_context()->ReturnInstruction(instr, expr->id()); | 4797 ast_context()->ReturnInstruction(instr, expr->id()); |
4794 } | 4798 } |
4795 | 4799 |
4796 | 4800 |
4797 void HGraphBuilder::VisitBitNot(UnaryOperation* expr) { | 4801 void HGraphBuilder::VisitBitNot(UnaryOperation* expr) { |
4798 CHECK_ALIVE(VisitForValue(expr->expression())); | 4802 CHECK_ALIVE(VisitForValue(expr->expression())); |
4799 HValue* value = Pop(); | 4803 HValue* value = Pop(); |
| 4804 TypeInfo info = oracle()->UnaryType(expr); |
| 4805 if (info.IsUninitialized()) { |
| 4806 AddInstruction(new(zone()) HSoftDeoptimize); |
| 4807 } |
4800 HInstruction* instr = new(zone()) HBitNot(value); | 4808 HInstruction* instr = new(zone()) HBitNot(value); |
4801 ast_context()->ReturnInstruction(instr, expr->id()); | 4809 ast_context()->ReturnInstruction(instr, expr->id()); |
4802 } | 4810 } |
4803 | 4811 |
4804 | 4812 |
4805 void HGraphBuilder::VisitNot(UnaryOperation* expr) { | 4813 void HGraphBuilder::VisitNot(UnaryOperation* expr) { |
4806 // TODO(svenpanne) Perhaps a switch/virtual function is nicer here. | 4814 // TODO(svenpanne) Perhaps a switch/virtual function is nicer here. |
4807 if (ast_context()->IsTest()) { | 4815 if (ast_context()->IsTest()) { |
4808 TestContext* context = TestContext::cast(ast_context()); | 4816 TestContext* context = TestContext::cast(ast_context()); |
4809 VisitForControl(expr->expression(), | 4817 VisitForControl(expr->expression(), |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5006 Token::Value op) { | 5014 Token::Value op) { |
5007 ASSERT(op == Token::EQ || op == Token::EQ_STRICT); | 5015 ASSERT(op == Token::EQ || op == Token::EQ_STRICT); |
5008 AddInstruction(new(zone()) HCheckNonSmi(left)); | 5016 AddInstruction(new(zone()) HCheckNonSmi(left)); |
5009 AddInstruction(HCheckInstanceType::NewIsSymbol(left)); | 5017 AddInstruction(HCheckInstanceType::NewIsSymbol(left)); |
5010 AddInstruction(new(zone()) HCheckNonSmi(right)); | 5018 AddInstruction(new(zone()) HCheckNonSmi(right)); |
5011 AddInstruction(HCheckInstanceType::NewIsSymbol(right)); | 5019 AddInstruction(HCheckInstanceType::NewIsSymbol(right)); |
5012 return new(zone()) HCompareSymbolEq(left, right, op); | 5020 return new(zone()) HCompareSymbolEq(left, right, op); |
5013 } | 5021 } |
5014 | 5022 |
5015 | 5023 |
| 5024 |
5016 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, | 5025 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, |
5017 HValue* index) { | 5026 HValue* index) { |
5018 AddInstruction(new(zone()) HCheckNonSmi(string)); | 5027 AddInstruction(new(zone()) HCheckNonSmi(string)); |
5019 AddInstruction(HCheckInstanceType::NewIsString(string)); | 5028 AddInstruction(HCheckInstanceType::NewIsString(string)); |
5020 HStringLength* length = new(zone()) HStringLength(string); | 5029 HStringLength* length = new(zone()) HStringLength(string); |
5021 AddInstruction(length); | 5030 AddInstruction(length); |
5022 AddInstruction(new(zone()) HBoundsCheck(index, length)); | 5031 AddInstruction(new(zone()) HBoundsCheck(index, length)); |
5023 return new(zone()) HStringCharCodeAt(string, index); | 5032 return new(zone()) HStringCharCodeAt(string, index); |
5024 } | 5033 } |
5025 | 5034 |
5026 | 5035 |
5027 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, | 5036 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
5028 HValue* left, | 5037 HValue* left, |
5029 HValue* right) { | 5038 HValue* right) { |
5030 TypeInfo info = oracle()->BinaryType(expr); | 5039 TypeInfo info = oracle()->BinaryType(expr); |
5031 HInstruction* instr = BuildBinaryOperation(expr->op(), left, right, info); | 5040 if (info.IsUninitialized()) { |
| 5041 AddInstruction(new(zone()) HSoftDeoptimize); |
| 5042 info = TypeInfo::Unknown(); |
| 5043 } |
| 5044 HInstruction* instr = NULL; |
| 5045 switch (expr->op()) { |
| 5046 case Token::ADD: |
| 5047 if (info.IsString()) { |
| 5048 AddInstruction(new(zone()) HCheckNonSmi(left)); |
| 5049 AddInstruction(HCheckInstanceType::NewIsString(left)); |
| 5050 AddInstruction(new(zone()) HCheckNonSmi(right)); |
| 5051 AddInstruction(HCheckInstanceType::NewIsString(right)); |
| 5052 instr = new(zone()) HStringAdd(left, right); |
| 5053 } else { |
| 5054 instr = new(zone()) HAdd(left, right); |
| 5055 } |
| 5056 break; |
| 5057 case Token::SUB: |
| 5058 instr = new(zone()) HSub(left, right); |
| 5059 break; |
| 5060 case Token::MUL: |
| 5061 instr = new(zone()) HMul(left, right); |
| 5062 break; |
| 5063 case Token::MOD: |
| 5064 instr = new(zone()) HMod(left, right); |
| 5065 break; |
| 5066 case Token::DIV: |
| 5067 instr = new(zone()) HDiv(left, right); |
| 5068 break; |
| 5069 case Token::BIT_XOR: |
| 5070 instr = new(zone()) HBitXor(left, right); |
| 5071 break; |
| 5072 case Token::BIT_AND: |
| 5073 instr = new(zone()) HBitAnd(left, right); |
| 5074 break; |
| 5075 case Token::BIT_OR: |
| 5076 instr = new(zone()) HBitOr(left, right); |
| 5077 break; |
| 5078 case Token::SAR: |
| 5079 instr = new(zone()) HSar(left, right); |
| 5080 break; |
| 5081 case Token::SHR: |
| 5082 instr = new(zone()) HShr(left, right); |
| 5083 break; |
| 5084 case Token::SHL: |
| 5085 instr = new(zone()) HShl(left, right); |
| 5086 break; |
| 5087 default: |
| 5088 UNREACHABLE(); |
| 5089 } |
| 5090 |
5032 // If we hit an uninitialized binary op stub we will get type info | 5091 // If we hit an uninitialized binary op stub we will get type info |
5033 // for a smi operation. If one of the operands is a constant string | 5092 // for a smi operation. If one of the operands is a constant string |
5034 // do not generate code assuming it is a smi operation. | 5093 // do not generate code assuming it is a smi operation. |
5035 if (info.IsSmi() && | 5094 if (info.IsSmi() && |
5036 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || | 5095 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || |
5037 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { | 5096 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { |
5038 return instr; | 5097 return instr; |
5039 } | 5098 } |
5040 Representation rep = ToRepresentation(info); | 5099 Representation rep = ToRepresentation(info); |
5041 // We only generate either int32 or generic tagged bitwise operations. | 5100 // We only generate either int32 or generic tagged bitwise operations. |
5042 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { | 5101 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { |
5043 rep = Representation::Integer32(); | 5102 rep = Representation::Integer32(); |
5044 } | 5103 } |
5045 TraceRepresentation(expr->op(), info, instr, rep); | 5104 TraceRepresentation(expr->op(), info, instr, rep); |
5046 instr->AssumeRepresentation(rep); | 5105 instr->AssumeRepresentation(rep); |
5047 return instr; | 5106 return instr; |
5048 } | 5107 } |
5049 | 5108 |
5050 | 5109 |
5051 HInstruction* HGraphBuilder::BuildBinaryOperation( | |
5052 Token::Value op, HValue* left, HValue* right, TypeInfo info) { | |
5053 switch (op) { | |
5054 case Token::ADD: | |
5055 if (info.IsString()) { | |
5056 AddInstruction(new(zone()) HCheckNonSmi(left)); | |
5057 AddInstruction(HCheckInstanceType::NewIsString(left)); | |
5058 AddInstruction(new(zone()) HCheckNonSmi(right)); | |
5059 AddInstruction(HCheckInstanceType::NewIsString(right)); | |
5060 return new(zone()) HStringAdd(left, right); | |
5061 } else { | |
5062 return new(zone()) HAdd(left, right); | |
5063 } | |
5064 case Token::SUB: return new(zone()) HSub(left, right); | |
5065 case Token::MUL: return new(zone()) HMul(left, right); | |
5066 case Token::MOD: return new(zone()) HMod(left, right); | |
5067 case Token::DIV: return new(zone()) HDiv(left, right); | |
5068 case Token::BIT_XOR: return new(zone()) HBitXor(left, right); | |
5069 case Token::BIT_AND: return new(zone()) HBitAnd(left, right); | |
5070 case Token::BIT_OR: return new(zone()) HBitOr(left, right); | |
5071 case Token::SAR: return new(zone()) HSar(left, right); | |
5072 case Token::SHR: return new(zone()) HShr(left, right); | |
5073 case Token::SHL: return new(zone()) HShl(left, right); | |
5074 default: | |
5075 UNREACHABLE(); | |
5076 return NULL; | |
5077 } | |
5078 } | |
5079 | |
5080 | |
5081 // Check for the form (%_ClassOf(foo) === 'BarClass'). | 5110 // Check for the form (%_ClassOf(foo) === 'BarClass'). |
5082 static bool IsClassOfTest(CompareOperation* expr) { | 5111 static bool IsClassOfTest(CompareOperation* expr) { |
5083 if (expr->op() != Token::EQ_STRICT) return false; | 5112 if (expr->op() != Token::EQ_STRICT) return false; |
5084 CallRuntime* call = expr->left()->AsCallRuntime(); | 5113 CallRuntime* call = expr->left()->AsCallRuntime(); |
5085 if (call == NULL) return false; | 5114 if (call == NULL) return false; |
5086 Literal* literal = expr->right()->AsLiteral(); | 5115 Literal* literal = expr->right()->AsLiteral(); |
5087 if (literal == NULL) return false; | 5116 if (literal == NULL) return false; |
5088 if (!literal->handle()->IsString()) return false; | 5117 if (!literal->handle()->IsString()) return false; |
5089 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; | 5118 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; |
5090 ASSERT(call->arguments()->length() == 1); | 5119 ASSERT(call->arguments()->length() == 1); |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5268 right_literal != NULL && right_literal->handle()->IsString()) { | 5297 right_literal != NULL && right_literal->handle()->IsString()) { |
5269 CHECK_ALIVE(VisitForTypeOf(left_unary->expression())); | 5298 CHECK_ALIVE(VisitForTypeOf(left_unary->expression())); |
5270 HValue* left = Pop(); | 5299 HValue* left = Pop(); |
5271 HInstruction* instr = new(zone()) HTypeofIs(left, | 5300 HInstruction* instr = new(zone()) HTypeofIs(left, |
5272 Handle<String>::cast(right_literal->handle())); | 5301 Handle<String>::cast(right_literal->handle())); |
5273 instr->set_position(expr->position()); | 5302 instr->set_position(expr->position()); |
5274 ast_context()->ReturnInstruction(instr, expr->id()); | 5303 ast_context()->ReturnInstruction(instr, expr->id()); |
5275 return; | 5304 return; |
5276 } | 5305 } |
5277 | 5306 |
| 5307 TypeInfo type_info = oracle()->CompareType(expr); |
| 5308 // Check if this expression was ever executed according to type feedback. |
| 5309 if (type_info.IsUninitialized()) { |
| 5310 AddInstruction(new(zone()) HSoftDeoptimize); |
| 5311 type_info = TypeInfo::Unknown(); |
| 5312 } |
| 5313 |
5278 CHECK_ALIVE(VisitForValue(expr->left())); | 5314 CHECK_ALIVE(VisitForValue(expr->left())); |
5279 CHECK_ALIVE(VisitForValue(expr->right())); | 5315 CHECK_ALIVE(VisitForValue(expr->right())); |
5280 | 5316 |
5281 HValue* right = Pop(); | 5317 HValue* right = Pop(); |
5282 HValue* left = Pop(); | 5318 HValue* left = Pop(); |
5283 Token::Value op = expr->op(); | 5319 Token::Value op = expr->op(); |
5284 | 5320 |
5285 TypeInfo type_info = oracle()->CompareType(expr); | |
5286 HInstruction* instr = NULL; | 5321 HInstruction* instr = NULL; |
5287 if (op == Token::INSTANCEOF) { | 5322 if (op == Token::INSTANCEOF) { |
5288 // Check to see if the rhs of the instanceof is a global function not | 5323 // Check to see if the rhs of the instanceof is a global function not |
5289 // residing in new space. If it is we assume that the function will stay the | 5324 // residing in new space. If it is we assume that the function will stay the |
5290 // same. | 5325 // same. |
5291 Handle<JSFunction> target = Handle<JSFunction>::null(); | 5326 Handle<JSFunction> target = Handle<JSFunction>::null(); |
5292 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); | 5327 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); |
5293 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); | 5328 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); |
5294 if (global_function && | 5329 if (global_function && |
5295 info()->has_global_object() && | 5330 info()->has_global_object() && |
(...skipping 1019 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6315 } | 6350 } |
6316 } | 6351 } |
6317 | 6352 |
6318 #ifdef DEBUG | 6353 #ifdef DEBUG |
6319 if (graph_ != NULL) graph_->Verify(); | 6354 if (graph_ != NULL) graph_->Verify(); |
6320 if (allocator_ != NULL) allocator_->Verify(); | 6355 if (allocator_ != NULL) allocator_->Verify(); |
6321 #endif | 6356 #endif |
6322 } | 6357 } |
6323 | 6358 |
6324 } } // namespace v8::internal | 6359 } } // namespace v8::internal |
OLD | NEW |