| OLD | NEW |
| 1 // Copyright 2010 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 | 121 |
| 122 HSimulate* HBasicBlock::CreateSimulate(int id) { | 122 HSimulate* HBasicBlock::CreateSimulate(int id) { |
| 123 ASSERT(HasEnvironment()); | 123 ASSERT(HasEnvironment()); |
| 124 HEnvironment* environment = last_environment(); | 124 HEnvironment* environment = last_environment(); |
| 125 ASSERT(id == AstNode::kNoNumber || | 125 ASSERT(id == AstNode::kNoNumber || |
| 126 environment->closure()->shared()->VerifyBailoutId(id)); | 126 environment->closure()->shared()->VerifyBailoutId(id)); |
| 127 | 127 |
| 128 int push_count = environment->push_count(); | 128 int push_count = environment->push_count(); |
| 129 int pop_count = environment->pop_count(); | 129 int pop_count = environment->pop_count(); |
| 130 | 130 |
| 131 int length = environment->values()->length(); | 131 int length = environment->length(); |
| 132 HSimulate* instr = new HSimulate(id, pop_count, length); | 132 HSimulate* instr = new HSimulate(id, pop_count, length); |
| 133 for (int i = push_count - 1; i >= 0; --i) { | 133 for (int i = push_count - 1; i >= 0; --i) { |
| 134 instr->AddPushedValue(environment->ExpressionStackAt(i)); | 134 instr->AddPushedValue(environment->ExpressionStackAt(i)); |
| 135 } | 135 } |
| 136 for (int i = 0; i < environment->assigned_variables()->length(); ++i) { | 136 for (int i = 0; i < environment->assigned_variables()->length(); ++i) { |
| 137 int index = environment->assigned_variables()->at(i); | 137 int index = environment->assigned_variables()->at(i); |
| 138 instr->AddAssignedValue(index, environment->Lookup(index)); | 138 instr->AddAssignedValue(index, environment->Lookup(index)); |
| 139 } | 139 } |
| 140 environment->ClearHistory(); | 140 environment->ClearHistory(); |
| 141 return instr; | 141 return instr; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 | 215 |
| 216 | 216 |
| 217 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { | 217 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { |
| 218 if (!predecessors_.is_empty()) { | 218 if (!predecessors_.is_empty()) { |
| 219 // Only loop header blocks can have a predecessor added after | 219 // Only loop header blocks can have a predecessor added after |
| 220 // instructions have been added to the block (they have phis for all | 220 // instructions have been added to the block (they have phis for all |
| 221 // values in the environment, these phis may be eliminated later). | 221 // values in the environment, these phis may be eliminated later). |
| 222 ASSERT(IsLoopHeader() || first_ == NULL); | 222 ASSERT(IsLoopHeader() || first_ == NULL); |
| 223 HEnvironment* incoming_env = pred->last_environment(); | 223 HEnvironment* incoming_env = pred->last_environment(); |
| 224 if (IsLoopHeader()) { | 224 if (IsLoopHeader()) { |
| 225 ASSERT(phis()->length() == incoming_env->values()->length()); | 225 ASSERT(phis()->length() == incoming_env->length()); |
| 226 for (int i = 0; i < phis_.length(); ++i) { | 226 for (int i = 0; i < phis_.length(); ++i) { |
| 227 phis_[i]->AddInput(incoming_env->values()->at(i)); | 227 phis_[i]->AddInput(incoming_env->values()->at(i)); |
| 228 } | 228 } |
| 229 } else { | 229 } else { |
| 230 last_environment()->AddIncomingEdge(this, pred->last_environment()); | 230 last_environment()->AddIncomingEdge(this, pred->last_environment()); |
| 231 } | 231 } |
| 232 } else if (!HasEnvironment() && !IsFinished()) { | 232 } else if (!HasEnvironment() && !IsFinished()) { |
| 233 ASSERT(!IsLoopHeader()); | 233 ASSERT(!IsLoopHeader()); |
| 234 SetInitialEnvironment(pred->last_environment()->Copy()); | 234 SetInitialEnvironment(pred->last_environment()->Copy()); |
| 235 } | 235 } |
| (...skipping 1739 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1975 } | 1975 } |
| 1976 } | 1976 } |
| 1977 | 1977 |
| 1978 | 1978 |
| 1979 // Implementation of utility classes to represent an expression's context in | 1979 // Implementation of utility classes to represent an expression's context in |
| 1980 // the AST. | 1980 // the AST. |
| 1981 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) | 1981 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
| 1982 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { | 1982 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { |
| 1983 owner->set_ast_context(this); // Push. | 1983 owner->set_ast_context(this); // Push. |
| 1984 #ifdef DEBUG | 1984 #ifdef DEBUG |
| 1985 original_count_ = owner->environment()->total_count(); | 1985 original_length_ = owner->environment()->length(); |
| 1986 #endif | 1986 #endif |
| 1987 } | 1987 } |
| 1988 | 1988 |
| 1989 | 1989 |
| 1990 AstContext::~AstContext() { | 1990 AstContext::~AstContext() { |
| 1991 owner_->set_ast_context(outer_); // Pop. | 1991 owner_->set_ast_context(outer_); // Pop. |
| 1992 } | 1992 } |
| 1993 | 1993 |
| 1994 | 1994 |
| 1995 EffectContext::~EffectContext() { | 1995 EffectContext::~EffectContext() { |
| 1996 ASSERT(owner()->HasStackOverflow() || | 1996 ASSERT(owner()->HasStackOverflow() || |
| 1997 !owner()->subgraph()->HasExit() || | 1997 !owner()->subgraph()->HasExit() || |
| 1998 owner()->environment()->total_count() == original_count_); | 1998 owner()->environment()->length() == original_length_); |
| 1999 } | 1999 } |
| 2000 | 2000 |
| 2001 | 2001 |
| 2002 ValueContext::~ValueContext() { | 2002 ValueContext::~ValueContext() { |
| 2003 ASSERT(owner()->HasStackOverflow() || | 2003 ASSERT(owner()->HasStackOverflow() || |
| 2004 !owner()->subgraph()->HasExit() || | 2004 !owner()->subgraph()->HasExit() || |
| 2005 owner()->environment()->total_count() == original_count_ + 1); | 2005 owner()->environment()->length() == original_length_ + 1); |
| 2006 } | 2006 } |
| 2007 | 2007 |
| 2008 | 2008 |
| 2009 void EffectContext::ReturnValue(HValue* value) { | 2009 void EffectContext::ReturnValue(HValue* value) { |
| 2010 // The value is simply ignored. | 2010 // The value is simply ignored. |
| 2011 } | 2011 } |
| 2012 | 2012 |
| 2013 | 2013 |
| 2014 void ValueContext::ReturnValue(HValue* value) { | 2014 void ValueContext::ReturnValue(HValue* value) { |
| 2015 // The value is tracked in the bailout environment, and communicated | 2015 // The value is tracked in the bailout environment, and communicated |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2336 | 2336 |
| 2337 // Set the initial values of parameters including "this". "This" has | 2337 // Set the initial values of parameters including "this". "This" has |
| 2338 // parameter index 0. | 2338 // parameter index 0. |
| 2339 int count = scope->num_parameters() + 1; | 2339 int count = scope->num_parameters() + 1; |
| 2340 for (int i = 0; i < count; ++i) { | 2340 for (int i = 0; i < count; ++i) { |
| 2341 HInstruction* parameter = AddInstruction(new HParameter(i)); | 2341 HInstruction* parameter = AddInstruction(new HParameter(i)); |
| 2342 environment()->Bind(i, parameter); | 2342 environment()->Bind(i, parameter); |
| 2343 } | 2343 } |
| 2344 | 2344 |
| 2345 // Set the initial values of stack-allocated locals. | 2345 // Set the initial values of stack-allocated locals. |
| 2346 for (int i = count; i < environment()->values()->length(); ++i) { | 2346 for (int i = count; i < environment()->length(); ++i) { |
| 2347 environment()->Bind(i, undefined_constant); | 2347 environment()->Bind(i, undefined_constant); |
| 2348 } | 2348 } |
| 2349 | 2349 |
| 2350 // Handle the arguments and arguments shadow variables specially (they do | 2350 // Handle the arguments and arguments shadow variables specially (they do |
| 2351 // not have declarations). | 2351 // not have declarations). |
| 2352 if (scope->arguments() != NULL) { | 2352 if (scope->arguments() != NULL) { |
| 2353 HArgumentsObject* object = new HArgumentsObject; | 2353 HArgumentsObject* object = new HArgumentsObject; |
| 2354 AddInstruction(object); | 2354 AddInstruction(object); |
| 2355 graph()->SetArgumentsObject(object); | 2355 graph()->SetArgumentsObject(object); |
| 2356 environment()->Bind(scope->arguments(), object); | 2356 environment()->Bind(scope->arguments(), object); |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2695 HValue* true_value = graph()->GetConstantTrue(); | 2695 HValue* true_value = graph()->GetConstantTrue(); |
| 2696 HBranch* branch = new HBranch(non_osr_entry, osr_entry, true_value); | 2696 HBranch* branch = new HBranch(non_osr_entry, osr_entry, true_value); |
| 2697 exit_block()->Finish(branch); | 2697 exit_block()->Finish(branch); |
| 2698 | 2698 |
| 2699 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 2699 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 2700 non_osr_entry->Goto(loop_predecessor); | 2700 non_osr_entry->Goto(loop_predecessor); |
| 2701 | 2701 |
| 2702 int osr_entry_id = statement->OsrEntryId(); | 2702 int osr_entry_id = statement->OsrEntryId(); |
| 2703 // We want the correct environment at the OsrEntry instruction. Build | 2703 // We want the correct environment at the OsrEntry instruction. Build |
| 2704 // it explicitly. The expression stack should be empty. | 2704 // it explicitly. The expression stack should be empty. |
| 2705 int count = osr_entry->last_environment()->total_count(); | 2705 int count = osr_entry->last_environment()->length(); |
| 2706 ASSERT(count == (osr_entry->last_environment()->parameter_count() + | 2706 ASSERT(count == (osr_entry->last_environment()->parameter_count() + |
| 2707 osr_entry->last_environment()->local_count())); | 2707 osr_entry->last_environment()->local_count())); |
| 2708 for (int i = 0; i < count; ++i) { | 2708 for (int i = 0; i < count; ++i) { |
| 2709 HUnknownOSRValue* unknown = new HUnknownOSRValue; | 2709 HUnknownOSRValue* unknown = new HUnknownOSRValue; |
| 2710 osr_entry->AddInstruction(unknown); | 2710 osr_entry->AddInstruction(unknown); |
| 2711 osr_entry->last_environment()->Bind(i, unknown); | 2711 osr_entry->last_environment()->Bind(i, unknown); |
| 2712 } | 2712 } |
| 2713 | 2713 |
| 2714 osr_entry->AddSimulate(osr_entry_id); | 2714 osr_entry->AddSimulate(osr_entry_id); |
| 2715 osr_entry->AddInstruction(new HOsrEntry(osr_entry_id)); | 2715 osr_entry->AddInstruction(new HOsrEntry(osr_entry_id)); |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3096 current_subgraph_->exit_block()->Finish( | 3096 current_subgraph_->exit_block()->Finish( |
| 3097 new HCompareMapAndBranch(receiver, | 3097 new HCompareMapAndBranch(receiver, |
| 3098 Handle<Map>(maps->first()), | 3098 Handle<Map>(maps->first()), |
| 3099 subgraphs->first()->entry_block(), | 3099 subgraphs->first()->entry_block(), |
| 3100 else_subgraph->entry_block())); | 3100 else_subgraph->entry_block())); |
| 3101 | 3101 |
| 3102 // Join all the call subgraphs in a new basic block and make | 3102 // Join all the call subgraphs in a new basic block and make |
| 3103 // this basic block the current basic block. | 3103 // this basic block the current basic block. |
| 3104 HBasicBlock* join_block = graph_->CreateBasicBlock(); | 3104 HBasicBlock* join_block = graph_->CreateBasicBlock(); |
| 3105 for (int i = 0; i < subgraphs->length(); ++i) { | 3105 for (int i = 0; i < subgraphs->length(); ++i) { |
| 3106 if (subgraphs->at(i)->HasExit()) { | 3106 HSubgraph* subgraph = subgraphs->at(i); |
| 3107 subgraphs->at(i)->exit_block()->Goto(join_block); | 3107 if (subgraph->HasExit()) { |
| 3108 // In an effect context the value of the type switch is not needed. |
| 3109 // There is no need to merge it at the join block only to discard it. |
| 3110 HBasicBlock* subgraph_exit = subgraph->exit_block(); |
| 3111 if (ast_context()->IsEffect()) { |
| 3112 subgraph_exit->last_environment()->Drop(1); |
| 3113 } |
| 3114 subgraph_exit->Goto(join_block); |
| 3108 } | 3115 } |
| 3109 } | 3116 } |
| 3110 | 3117 |
| 3111 if (join_block->predecessors()->is_empty()) return NULL; | 3118 if (join_block->predecessors()->is_empty()) return NULL; |
| 3112 join_block->SetJoinId(join_id); | 3119 join_block->SetJoinId(join_id); |
| 3113 return join_block; | 3120 return join_block; |
| 3114 } | 3121 } |
| 3115 | 3122 |
| 3116 | 3123 |
| 3117 // Sets the lookup result and returns true if the store can be inlined. | 3124 // Sets the lookup result and returns true if the store can be inlined. |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3235 } | 3242 } |
| 3236 } | 3243 } |
| 3237 | 3244 |
| 3238 // If none of the properties were named fields we generate a | 3245 // If none of the properties were named fields we generate a |
| 3239 // generic store. | 3246 // generic store. |
| 3240 if (maps.length() == 0) { | 3247 if (maps.length() == 0) { |
| 3241 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | 3248 HInstruction* instr = new HStoreNamedGeneric(object, name, value); |
| 3242 Push(value); | 3249 Push(value); |
| 3243 instr->set_position(expr->position()); | 3250 instr->set_position(expr->position()); |
| 3244 AddInstruction(instr); | 3251 AddInstruction(instr); |
| 3245 if (instr->HasSideEffects()) AddSimulate(expr->id()); | 3252 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3253 ast_context()->ReturnValue(Pop()); |
| 3246 } else { | 3254 } else { |
| 3247 // Build subgraph for generic store through IC. | 3255 // Build subgraph for generic store through IC. |
| 3248 { | 3256 { |
| 3249 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3257 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3250 SubgraphScope scope(this, subgraph); | 3258 SubgraphScope scope(this, subgraph); |
| 3251 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3259 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3252 subgraph->FinishExit(new HDeoptimize()); | 3260 subgraph->FinishExit(new HDeoptimize()); |
| 3253 } else { | 3261 } else { |
| 3254 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | 3262 HInstruction* instr = new HStoreNamedGeneric(object, name, value); |
| 3255 Push(value); | 3263 Push(value); |
| 3256 instr->set_position(expr->position()); | 3264 instr->set_position(expr->position()); |
| 3257 AddInstruction(instr); | 3265 AddInstruction(instr); |
| 3258 } | 3266 } |
| 3259 subgraphs.Add(subgraph); | 3267 subgraphs.Add(subgraph); |
| 3260 } | 3268 } |
| 3261 | 3269 |
| 3262 HBasicBlock* new_exit_block = | 3270 HBasicBlock* new_exit_block = |
| 3263 BuildTypeSwitch(&maps, &subgraphs, object, expr->AssignmentId()); | 3271 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); |
| 3264 subgraph()->set_exit_block(new_exit_block); | 3272 subgraph()->set_exit_block(new_exit_block); |
| 3273 // In an effect context, we did not materialized the value in the |
| 3274 // predecessor environments so there's no need to handle it here. |
| 3275 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { |
| 3276 ast_context()->ReturnValue(Pop()); |
| 3277 } |
| 3265 } | 3278 } |
| 3266 | |
| 3267 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); | |
| 3268 } | 3279 } |
| 3269 | 3280 |
| 3270 | 3281 |
| 3271 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3282 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3272 Property* prop = expr->target()->AsProperty(); | 3283 Property* prop = expr->target()->AsProperty(); |
| 3273 ASSERT(prop != NULL); | 3284 ASSERT(prop != NULL); |
| 3274 expr->RecordTypeFeedback(oracle()); | 3285 expr->RecordTypeFeedback(oracle()); |
| 3275 VISIT_FOR_VALUE(prop->obj()); | 3286 VISIT_FOR_VALUE(prop->obj()); |
| 3276 | 3287 |
| 3277 HValue* value = NULL; | 3288 HValue* value = NULL; |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3541 } else { | 3552 } else { |
| 3542 needs_generic = true; | 3553 needs_generic = true; |
| 3543 } | 3554 } |
| 3544 } | 3555 } |
| 3545 | 3556 |
| 3546 // If none of the properties were named fields we generate a | 3557 // If none of the properties were named fields we generate a |
| 3547 // generic load. | 3558 // generic load. |
| 3548 if (maps.length() == 0) { | 3559 if (maps.length() == 0) { |
| 3549 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3560 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3550 instr->set_position(expr->position()); | 3561 instr->set_position(expr->position()); |
| 3551 PushAndAdd(instr); | 3562 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3552 if (instr->HasSideEffects()) AddSimulate(expr->id()); | |
| 3553 } else { | 3563 } else { |
| 3554 // Build subgraph for generic load through IC. | 3564 // Build subgraph for generic load through IC. |
| 3555 { | 3565 { |
| 3556 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3566 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3557 SubgraphScope scope(this, subgraph); | 3567 SubgraphScope scope(this, subgraph); |
| 3558 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3568 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3559 subgraph->FinishExit(new HDeoptimize()); | 3569 subgraph->FinishExit(new HDeoptimize()); |
| 3560 } else { | 3570 } else { |
| 3561 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3571 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3562 instr->set_position(expr->position()); | 3572 instr->set_position(expr->position()); |
| 3563 PushAndAdd(instr); | 3573 PushAndAdd(instr); |
| 3564 } | 3574 } |
| 3565 subgraphs.Add(subgraph); | 3575 subgraphs.Add(subgraph); |
| 3566 } | 3576 } |
| 3567 | 3577 |
| 3568 HBasicBlock* new_exit_block = | 3578 HBasicBlock* new_exit_block = |
| 3569 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | 3579 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); |
| 3570 subgraph()->set_exit_block(new_exit_block); | 3580 subgraph()->set_exit_block(new_exit_block); |
| 3581 // In an effect context, we did not materialized the value in the |
| 3582 // predecessor environments so there's no need to handle it here. |
| 3583 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { |
| 3584 ast_context()->ReturnValue(Pop()); |
| 3585 } |
| 3571 } | 3586 } |
| 3572 | |
| 3573 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); | |
| 3574 } | 3587 } |
| 3575 | 3588 |
| 3576 | 3589 |
| 3577 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3590 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3578 Property* expr, | 3591 Property* expr, |
| 3579 Handle<Map> type, | 3592 Handle<Map> type, |
| 3580 LookupResult* lookup, | 3593 LookupResult* lookup, |
| 3581 bool smi_and_map_check) { | 3594 bool smi_and_map_check) { |
| 3582 if (smi_and_map_check) { | 3595 if (smi_and_map_check) { |
| 3583 AddInstruction(new HCheckNonSmi(object)); | 3596 AddInstruction(new HCheckNonSmi(object)); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3636 | 3649 |
| 3637 | 3650 |
| 3638 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, | 3651 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, |
| 3639 HValue* key, | 3652 HValue* key, |
| 3640 Property* expr) { | 3653 Property* expr) { |
| 3641 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3654 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); |
| 3642 AddInstruction(new HCheckNonSmi(object)); | 3655 AddInstruction(new HCheckNonSmi(object)); |
| 3643 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3656 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3644 ASSERT(map->has_fast_elements()); | 3657 ASSERT(map->has_fast_elements()); |
| 3645 AddInstruction(new HCheckMap(object, map)); | 3658 AddInstruction(new HCheckMap(object, map)); |
| 3646 HInstruction* elements = AddInstruction(new HLoadElements(object)); | 3659 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); |
| 3647 HInstruction* length = AddInstruction(new HArrayLength(elements)); | 3660 HLoadElements* elements = new HLoadElements(object); |
| 3648 AddInstruction(new HBoundsCheck(key, length)); | 3661 HInstruction* length = NULL; |
| 3662 if (is_array) { |
| 3663 length = AddInstruction(new HJSArrayLength(object)); |
| 3664 AddInstruction(new HBoundsCheck(key, length)); |
| 3665 AddInstruction(elements); |
| 3666 } else { |
| 3667 AddInstruction(elements); |
| 3668 length = AddInstruction(new HFixedArrayLength(elements)); |
| 3669 AddInstruction(new HBoundsCheck(key, length)); |
| 3670 } |
| 3649 return new HLoadKeyedFastElement(elements, key); | 3671 return new HLoadKeyedFastElement(elements, key); |
| 3650 } | 3672 } |
| 3651 | 3673 |
| 3652 | 3674 |
| 3653 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, | 3675 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
| 3654 HValue* key, | 3676 HValue* key, |
| 3655 HValue* value) { | 3677 HValue* value) { |
| 3656 return new HStoreKeyedGeneric(object, key, value); | 3678 return new HStoreKeyedGeneric(object, key, value); |
| 3657 } | 3679 } |
| 3658 | 3680 |
| 3659 | 3681 |
| 3660 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, | 3682 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, |
| 3661 HValue* key, | 3683 HValue* key, |
| 3662 HValue* val, | 3684 HValue* val, |
| 3663 Expression* expr) { | 3685 Expression* expr) { |
| 3664 ASSERT(expr->IsMonomorphic()); | 3686 ASSERT(expr->IsMonomorphic()); |
| 3665 AddInstruction(new HCheckNonSmi(object)); | 3687 AddInstruction(new HCheckNonSmi(object)); |
| 3666 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3688 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3667 ASSERT(map->has_fast_elements()); | 3689 ASSERT(map->has_fast_elements()); |
| 3668 AddInstruction(new HCheckMap(object, map)); | 3690 AddInstruction(new HCheckMap(object, map)); |
| 3669 HInstruction* elements = AddInstruction(new HLoadElements(object)); | 3691 HInstruction* elements = AddInstruction(new HLoadElements(object)); |
| 3670 AddInstruction(new HCheckMap(elements, FACTORY->fixed_array_map())); | 3692 AddInstruction(new HCheckMap(elements, FACTORY->fixed_array_map())); |
| 3671 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); | 3693 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); |
| 3672 HInstruction* length = NULL; | 3694 HInstruction* length = NULL; |
| 3673 if (is_array) { | 3695 if (is_array) { |
| 3674 length = AddInstruction(new HArrayLength(object)); | 3696 length = AddInstruction(new HJSArrayLength(object)); |
| 3675 } else { | 3697 } else { |
| 3676 length = AddInstruction(new HArrayLength(elements)); | 3698 length = AddInstruction(new HFixedArrayLength(elements)); |
| 3677 } | 3699 } |
| 3678 AddInstruction(new HBoundsCheck(key, length)); | 3700 AddInstruction(new HBoundsCheck(key, length)); |
| 3679 return new HStoreKeyedFastElement(elements, key, val); | 3701 return new HStoreKeyedFastElement(elements, key, val); |
| 3680 } | 3702 } |
| 3681 | 3703 |
| 3682 | 3704 |
| 3683 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 3705 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
| 3684 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 3706 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
| 3685 if (proxy == NULL) return false; | 3707 if (proxy == NULL) return false; |
| 3686 if (!proxy->var()->IsStackAllocated()) return false; | 3708 if (!proxy->var()->IsStackAllocated()) return false; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3713 | 3735 |
| 3714 if (TryArgumentsAccess(expr)) return; | 3736 if (TryArgumentsAccess(expr)) return; |
| 3715 CHECK_BAILOUT; | 3737 CHECK_BAILOUT; |
| 3716 | 3738 |
| 3717 VISIT_FOR_VALUE(expr->obj()); | 3739 VISIT_FOR_VALUE(expr->obj()); |
| 3718 | 3740 |
| 3719 HInstruction* instr = NULL; | 3741 HInstruction* instr = NULL; |
| 3720 if (expr->IsArrayLength()) { | 3742 if (expr->IsArrayLength()) { |
| 3721 HValue* array = Pop(); | 3743 HValue* array = Pop(); |
| 3722 AddInstruction(new HCheckNonSmi(array)); | 3744 AddInstruction(new HCheckNonSmi(array)); |
| 3723 instr = new HArrayLength(array); | 3745 AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE)); |
| 3746 instr = new HJSArrayLength(array); |
| 3747 |
| 3748 } else if (expr->IsFunctionPrototype()) { |
| 3749 HValue* function = Pop(); |
| 3750 AddInstruction(new HCheckNonSmi(function)); |
| 3751 instr = new HLoadFunctionPrototype(function); |
| 3724 | 3752 |
| 3725 } else if (expr->key()->IsPropertyName()) { | 3753 } else if (expr->key()->IsPropertyName()) { |
| 3726 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 3754 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 3727 ZoneMapList* types = expr->GetReceiverTypes(); | 3755 ZoneMapList* types = expr->GetReceiverTypes(); |
| 3728 | 3756 |
| 3729 HValue* obj = Pop(); | 3757 HValue* obj = Pop(); |
| 3730 if (expr->IsMonomorphic()) { | 3758 if (expr->IsMonomorphic()) { |
| 3731 instr = BuildLoadNamed(obj, expr, types->first(), name); | 3759 instr = BuildLoadNamed(obj, expr, types->first(), name); |
| 3732 } else if (types != NULL && types->length() > 1) { | 3760 } else if (types != NULL && types->length() > 1) { |
| 3733 HandlePolymorphicLoadNamedField(expr, obj, types, name); | 3761 HandlePolymorphicLoadNamedField(expr, obj, types, name); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3760 Handle<Map> receiver_map, | 3788 Handle<Map> receiver_map, |
| 3761 bool smi_and_map_check) { | 3789 bool smi_and_map_check) { |
| 3762 // Constant functions have the nice property that the map will change if they | 3790 // Constant functions have the nice property that the map will change if they |
| 3763 // are overwritten. Therefore it is enough to check the map of the holder and | 3791 // are overwritten. Therefore it is enough to check the map of the holder and |
| 3764 // its prototypes. | 3792 // its prototypes. |
| 3765 if (smi_and_map_check) { | 3793 if (smi_and_map_check) { |
| 3766 AddInstruction(new HCheckNonSmi(receiver)); | 3794 AddInstruction(new HCheckNonSmi(receiver)); |
| 3767 AddInstruction(new HCheckMap(receiver, receiver_map)); | 3795 AddInstruction(new HCheckMap(receiver, receiver_map)); |
| 3768 } | 3796 } |
| 3769 if (!expr->holder().is_null()) { | 3797 if (!expr->holder().is_null()) { |
| 3770 AddInstruction(new HCheckPrototypeMaps(receiver, | 3798 AddInstruction(new HCheckPrototypeMaps( |
| 3771 expr->holder(), | 3799 Handle<JSObject>(JSObject::cast(receiver_map->prototype())), |
| 3772 receiver_map)); | 3800 expr->holder())); |
| 3773 } | 3801 } |
| 3774 } | 3802 } |
| 3775 | 3803 |
| 3776 | 3804 |
| 3777 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, | 3805 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
| 3778 HValue* receiver, | 3806 HValue* receiver, |
| 3779 ZoneMapList* types, | 3807 ZoneMapList* types, |
| 3780 Handle<String> name) { | 3808 Handle<String> name) { |
| 3781 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 3809 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 3782 int number_of_types = Min(types->length(), kMaxCallPolymorphism); | 3810 int number_of_types = Min(types->length(), kMaxCallPolymorphism); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3834 call->set_position(expr->position()); | 3862 call->set_position(expr->position()); |
| 3835 ProcessCall(call); | 3863 ProcessCall(call); |
| 3836 PushAndAdd(call); | 3864 PushAndAdd(call); |
| 3837 } | 3865 } |
| 3838 subgraphs.Add(subgraph); | 3866 subgraphs.Add(subgraph); |
| 3839 } | 3867 } |
| 3840 | 3868 |
| 3841 HBasicBlock* new_exit_block = | 3869 HBasicBlock* new_exit_block = |
| 3842 BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); | 3870 BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); |
| 3843 subgraph()->set_exit_block(new_exit_block); | 3871 subgraph()->set_exit_block(new_exit_block); |
| 3844 if (new_exit_block != NULL) ast_context()->ReturnValue(Pop()); | 3872 // In an effect context, we did not materialized the value in the |
| 3873 // predecessor environments so there's no need to handle it here. |
| 3874 if (new_exit_block != NULL && !ast_context()->IsEffect()) { |
| 3875 ast_context()->ReturnValue(Pop()); |
| 3876 } |
| 3845 } | 3877 } |
| 3846 } | 3878 } |
| 3847 | 3879 |
| 3848 | 3880 |
| 3849 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { | 3881 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { |
| 3850 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); | 3882 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); |
| 3851 SmartPointer<char> caller = | 3883 SmartPointer<char> caller = |
| 3852 graph()->info()->function()->debug_name()->ToCString(); | 3884 graph()->info()->function()->debug_name()->ToCString(); |
| 3853 if (result) { | 3885 if (result) { |
| 3854 PrintF("Inlined %s called from %s.\n", *callee, *caller); | 3886 PrintF("Inlined %s called from %s.\n", *callee, *caller); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3970 if_false->MarkAsInlineReturnTarget(); | 4002 if_false->MarkAsInlineReturnTarget(); |
| 3971 // AstContext constructor pushes on the context stack. | 4003 // AstContext constructor pushes on the context stack. |
| 3972 test_context = new TestContext(this, if_true, if_false); | 4004 test_context = new TestContext(this, if_true, if_false); |
| 3973 function_return_ = NULL; | 4005 function_return_ = NULL; |
| 3974 } else { | 4006 } else { |
| 3975 // Inlined body is treated as if it occurs in the original call context. | 4007 // Inlined body is treated as if it occurs in the original call context. |
| 3976 function_return_ = graph()->CreateBasicBlock(); | 4008 function_return_ = graph()->CreateBasicBlock(); |
| 3977 function_return_->MarkAsInlineReturnTarget(); | 4009 function_return_->MarkAsInlineReturnTarget(); |
| 3978 } | 4010 } |
| 3979 call_context_ = ast_context(); | 4011 call_context_ = ast_context(); |
| 3980 TypeFeedbackOracle new_oracle(Handle<Code>(shared->code())); | 4012 TypeFeedbackOracle new_oracle( |
| 4013 Handle<Code>(shared->code()), |
| 4014 Handle<Context>(target->context()->global_context())); |
| 3981 oracle_ = &new_oracle; | 4015 oracle_ = &new_oracle; |
| 3982 graph()->info()->SetOsrAstId(AstNode::kNoNumber); | 4016 graph()->info()->SetOsrAstId(AstNode::kNoNumber); |
| 3983 | 4017 |
| 3984 HSubgraph* body = CreateInlinedSubgraph(env, target, function); | 4018 HSubgraph* body = CreateInlinedSubgraph(env, target, function); |
| 3985 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); | 4019 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); |
| 3986 AddToSubgraph(body, function->body()); | 4020 AddToSubgraph(body, function->body()); |
| 3987 if (HasStackOverflow()) { | 4021 if (HasStackOverflow()) { |
| 3988 // Bail out if the inline function did, as we cannot residualize a call | 4022 // Bail out if the inline function did, as we cannot residualize a call |
| 3989 // instead. | 4023 // instead. |
| 3990 delete test_context; | 4024 delete test_context; |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4172 if (!name->IsEqualTo(CStrVector("apply"))) return false; | 4206 if (!name->IsEqualTo(CStrVector("apply"))) return false; |
| 4173 | 4207 |
| 4174 ZoneList<Expression*>* args = expr->arguments(); | 4208 ZoneList<Expression*>* args = expr->arguments(); |
| 4175 if (args->length() != 2) return false; | 4209 if (args->length() != 2) return false; |
| 4176 | 4210 |
| 4177 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 4211 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 4178 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 4212 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 4179 HValue* arg_two_value = environment()->Lookup(arg_two->var()); | 4213 HValue* arg_two_value = environment()->Lookup(arg_two->var()); |
| 4180 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 4214 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
| 4181 | 4215 |
| 4182 if (!expr->IsMonomorphic()) return false; | 4216 if (!expr->IsMonomorphic() || |
| 4217 expr->check_type() != RECEIVER_MAP_CHECK) return false; |
| 4183 | 4218 |
| 4184 // Found pattern f.apply(receiver, arguments). | 4219 // Found pattern f.apply(receiver, arguments). |
| 4185 VisitForValue(prop->obj()); | 4220 VisitForValue(prop->obj()); |
| 4186 if (HasStackOverflow()) return false; | 4221 if (HasStackOverflow()) return false; |
| 4187 HValue* function = Pop(); | 4222 HValue* function = Pop(); |
| 4188 VisitForValue(args->at(0)); | 4223 VisitForValue(args->at(0)); |
| 4189 if (HasStackOverflow()) return false; | 4224 if (HasStackOverflow()) return false; |
| 4190 HValue* receiver = Pop(); | 4225 HValue* receiver = Pop(); |
| 4191 HInstruction* elements = AddInstruction(new HArgumentsElements); | 4226 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 4192 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 4227 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4241 HValue* receiver = VisitArgument(prop->obj()); | 4276 HValue* receiver = VisitArgument(prop->obj()); |
| 4242 CHECK_BAILOUT; | 4277 CHECK_BAILOUT; |
| 4243 VisitArgumentList(expr->arguments()); | 4278 VisitArgumentList(expr->arguments()); |
| 4244 CHECK_BAILOUT; | 4279 CHECK_BAILOUT; |
| 4245 | 4280 |
| 4246 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4281 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4247 | 4282 |
| 4248 expr->RecordTypeFeedback(oracle()); | 4283 expr->RecordTypeFeedback(oracle()); |
| 4249 ZoneMapList* types = expr->GetReceiverTypes(); | 4284 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4250 | 4285 |
| 4251 if (expr->IsMonomorphic()) { | 4286 if (expr->IsMonomorphic() && expr->check_type() == RECEIVER_MAP_CHECK) { |
| 4252 AddCheckConstantFunction(expr, receiver, types->first(), true); | 4287 AddCheckConstantFunction(expr, receiver, types->first(), true); |
| 4253 | 4288 |
| 4254 if (TryMathFunctionInline(expr)) { | 4289 if (TryMathFunctionInline(expr)) { |
| 4255 return; | 4290 return; |
| 4256 } else if (TryInline(expr)) { | 4291 } else if (TryInline(expr)) { |
| 4257 if (subgraph()->HasExit()) { | 4292 if (subgraph()->HasExit()) { |
| 4258 HValue* return_value = Pop(); | 4293 HValue* return_value = Pop(); |
| 4259 // If we inlined a function in a test context then we need to emit | 4294 // If we inlined a function in a test context then we need to emit |
| 4260 // a simulate here to shadow the ones at the end of the | 4295 // a simulate here to shadow the ones at the end of the |
| 4261 // predecessor blocks. Those environments contain the return | 4296 // predecessor blocks. Those environments contain the return |
| 4262 // value on top and do not correspond to any actual state of the | 4297 // value on top and do not correspond to any actual state of the |
| 4263 // unoptimized code. | 4298 // unoptimized code. |
| 4264 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | 4299 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4265 ast_context()->ReturnValue(return_value); | 4300 ast_context()->ReturnValue(return_value); |
| 4266 } | 4301 } |
| 4267 return; | 4302 return; |
| 4268 } else { | 4303 } else { |
| 4269 // Check for bailout, as the TryInline call in the if condition above | 4304 // Check for bailout, as the TryInline call in the if condition above |
| 4270 // might return false due to bailout during hydrogen processing. | 4305 // might return false due to bailout during hydrogen processing. |
| 4271 CHECK_BAILOUT; | 4306 CHECK_BAILOUT; |
| 4272 call = new HCallConstantFunction(expr->target(), argument_count); | 4307 call = new HCallConstantFunction(expr->target(), argument_count); |
| 4273 } | 4308 } |
| 4274 | 4309 |
| 4275 } else if (types != NULL && types->length() > 1) { | 4310 } else if (types != NULL && types->length() > 1) { |
| 4311 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 4276 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4312 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4277 return; | 4313 return; |
| 4278 | 4314 |
| 4279 } else { | 4315 } else { |
| 4280 call = new HCallNamed(name, argument_count); | 4316 call = new HCallNamed(name, argument_count); |
| 4281 } | 4317 } |
| 4282 | 4318 |
| 4283 } else { | 4319 } else { |
| 4284 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4320 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4285 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); | 4321 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); |
| (...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4840 VISIT_FOR_VALUE(expr->left()); | 4876 VISIT_FOR_VALUE(expr->left()); |
| 4841 VISIT_FOR_VALUE(expr->right()); | 4877 VISIT_FOR_VALUE(expr->right()); |
| 4842 | 4878 |
| 4843 HValue* right = Pop(); | 4879 HValue* right = Pop(); |
| 4844 HValue* left = Pop(); | 4880 HValue* left = Pop(); |
| 4845 Token::Value op = expr->op(); | 4881 Token::Value op = expr->op(); |
| 4846 | 4882 |
| 4847 TypeInfo info = oracle()->CompareType(expr, TypeFeedbackOracle::RESULT); | 4883 TypeInfo info = oracle()->CompareType(expr, TypeFeedbackOracle::RESULT); |
| 4848 HInstruction* instr = NULL; | 4884 HInstruction* instr = NULL; |
| 4849 if (op == Token::INSTANCEOF) { | 4885 if (op == Token::INSTANCEOF) { |
| 4850 instr = new HInstanceOf(left, right); | 4886 // Check to see if the rhs of the instanceof is a global function not |
| 4887 // residing in new space. If it is we assume that the function will stay the |
| 4888 // same. |
| 4889 Handle<JSFunction> target = Handle<JSFunction>::null(); |
| 4890 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); |
| 4891 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); |
| 4892 CompilationInfo* info = graph()->info(); |
| 4893 if (global_function && |
| 4894 info->has_global_object() && |
| 4895 !info->global_object()->IsAccessCheckNeeded()) { |
| 4896 Handle<String> name = var->name(); |
| 4897 Handle<GlobalObject> global(info->global_object()); |
| 4898 LookupResult lookup; |
| 4899 global->Lookup(*name, &lookup); |
| 4900 if (lookup.IsProperty() && |
| 4901 lookup.type() == NORMAL && |
| 4902 lookup.GetValue()->IsJSFunction()) { |
| 4903 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); |
| 4904 // If the function is in new space we assume it's more likely to |
| 4905 // change and thus prefer the general IC code. |
| 4906 if (!info->isolate()->heap()->InNewSpace(*candidate)) { |
| 4907 target = candidate; |
| 4908 } |
| 4909 } |
| 4910 } |
| 4911 |
| 4912 // If the target is not null we have found a known global function that is |
| 4913 // assumed to stay the same for this instanceof. |
| 4914 if (target.is_null()) { |
| 4915 instr = new HInstanceOf(left, right); |
| 4916 } else { |
| 4917 AddInstruction(new HCheckFunction(right, target)); |
| 4918 instr = new HInstanceOfKnownGlobal(left, target); |
| 4919 } |
| 4851 } else if (op == Token::IN) { | 4920 } else if (op == Token::IN) { |
| 4852 BAILOUT("Unsupported comparison: in"); | 4921 BAILOUT("Unsupported comparison: in"); |
| 4853 } else if (info.IsNonPrimitive()) { | 4922 } else if (info.IsNonPrimitive()) { |
| 4854 switch (op) { | 4923 switch (op) { |
| 4855 case Token::EQ: | 4924 case Token::EQ: |
| 4856 case Token::EQ_STRICT: { | 4925 case Token::EQ_STRICT: { |
| 4926 AddInstruction(new HCheckNonSmi(left)); |
| 4857 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); | 4927 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); |
| 4928 AddInstruction(new HCheckNonSmi(right)); |
| 4858 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); | 4929 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); |
| 4859 instr = new HCompareJSObjectEq(left, right); | 4930 instr = new HCompareJSObjectEq(left, right); |
| 4860 break; | 4931 break; |
| 4861 } | 4932 } |
| 4862 default: | 4933 default: |
| 4863 BAILOUT("Unsupported non-primitive compare"); | 4934 BAILOUT("Unsupported non-primitive compare"); |
| 4864 break; | 4935 break; |
| 4865 } | 4936 } |
| 4866 } else { | 4937 } else { |
| 4867 HCompare* compare = new HCompare(left, right, op); | 4938 HCompare* compare = new HCompare(left, right, op); |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5255 parameter_count_ = parameter_count; | 5326 parameter_count_ = parameter_count; |
| 5256 local_count_ = local_count; | 5327 local_count_ = local_count; |
| 5257 | 5328 |
| 5258 // Avoid reallocating the temporaries' backing store on the first Push. | 5329 // Avoid reallocating the temporaries' backing store on the first Push. |
| 5259 int total = parameter_count + local_count + stack_height; | 5330 int total = parameter_count + local_count + stack_height; |
| 5260 values_.Initialize(total + 4); | 5331 values_.Initialize(total + 4); |
| 5261 for (int i = 0; i < total; ++i) values_.Add(NULL); | 5332 for (int i = 0; i < total; ++i) values_.Add(NULL); |
| 5262 } | 5333 } |
| 5263 | 5334 |
| 5264 | 5335 |
| 5336 void HEnvironment::Initialize(const HEnvironment* other) { |
| 5337 closure_ = other->closure(); |
| 5338 values_.AddAll(other->values_); |
| 5339 assigned_variables_.AddAll(other->assigned_variables_); |
| 5340 parameter_count_ = other->parameter_count_; |
| 5341 local_count_ = other->local_count_; |
| 5342 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. |
| 5343 pop_count_ = other->pop_count_; |
| 5344 push_count_ = other->push_count_; |
| 5345 ast_id_ = other->ast_id_; |
| 5346 } |
| 5347 |
| 5348 |
| 5265 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { | 5349 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { |
| 5266 ASSERT(!block->IsLoopHeader()); | 5350 ASSERT(!block->IsLoopHeader()); |
| 5267 ASSERT(values_.length() == other->values_.length()); | 5351 ASSERT(values_.length() == other->values_.length()); |
| 5268 | 5352 |
| 5269 int length = values_.length(); | 5353 int length = values_.length(); |
| 5270 for (int i = 0; i < length; ++i) { | 5354 for (int i = 0; i < length; ++i) { |
| 5271 HValue* value = values_[i]; | 5355 HValue* value = values_[i]; |
| 5272 if (value != NULL && value->IsPhi() && value->block() == block) { | 5356 if (value != NULL && value->IsPhi() && value->block() == block) { |
| 5273 // There is already a phi for the i'th value. | 5357 // There is already a phi for the i'th value. |
| 5274 HPhi* phi = HPhi::cast(value); | 5358 HPhi* phi = HPhi::cast(value); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 5285 phi->AddInput(old_value); | 5369 phi->AddInput(old_value); |
| 5286 } | 5370 } |
| 5287 phi->AddInput(other->values_[i]); | 5371 phi->AddInput(other->values_[i]); |
| 5288 this->values_[i] = phi; | 5372 this->values_[i] = phi; |
| 5289 block->AddPhi(phi); | 5373 block->AddPhi(phi); |
| 5290 } | 5374 } |
| 5291 } | 5375 } |
| 5292 } | 5376 } |
| 5293 | 5377 |
| 5294 | 5378 |
| 5295 void HEnvironment::Initialize(const HEnvironment* other) { | 5379 void HEnvironment::Bind(int index, HValue* value) { |
| 5296 closure_ = other->closure(); | 5380 ASSERT(value != NULL); |
| 5297 values_.AddAll(other->values_); | 5381 if (!assigned_variables_.Contains(index)) { |
| 5298 assigned_variables_.AddAll(other->assigned_variables_); | 5382 assigned_variables_.Add(index); |
| 5299 parameter_count_ = other->parameter_count_; | 5383 } |
| 5300 local_count_ = other->local_count_; | 5384 values_[index] = value; |
| 5301 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. | |
| 5302 pop_count_ = other->pop_count_; | |
| 5303 push_count_ = other->push_count_; | |
| 5304 ast_id_ = other->ast_id_; | |
| 5305 } | 5385 } |
| 5306 | 5386 |
| 5307 | 5387 |
| 5308 int HEnvironment::IndexFor(Variable* variable) const { | 5388 bool HEnvironment::HasExpressionAt(int index) const { |
| 5309 Slot* slot = variable->AsSlot(); | 5389 return index >= parameter_count_ + local_count_; |
| 5310 ASSERT(slot != NULL && slot->IsStackAllocated()); | 5390 } |
| 5311 if (slot->type() == Slot::PARAMETER) { | 5391 |
| 5312 return slot->index() + 1; | 5392 |
| 5313 } else { | 5393 bool HEnvironment::ExpressionStackIsEmpty() const { |
| 5314 return parameter_count_ + slot->index(); | 5394 int first_expression = parameter_count() + local_count(); |
| 5395 ASSERT(length() >= first_expression); |
| 5396 return length() == first_expression; |
| 5397 } |
| 5398 |
| 5399 |
| 5400 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) { |
| 5401 int count = index_from_top + 1; |
| 5402 int index = values_.length() - count; |
| 5403 ASSERT(HasExpressionAt(index)); |
| 5404 // The push count must include at least the element in question or else |
| 5405 // the new value will not be included in this environment's history. |
| 5406 if (push_count_ < count) { |
| 5407 // This is the same effect as popping then re-pushing 'count' elements. |
| 5408 pop_count_ += (count - push_count_); |
| 5409 push_count_ = count; |
| 5410 } |
| 5411 values_[index] = value; |
| 5412 } |
| 5413 |
| 5414 |
| 5415 void HEnvironment::Drop(int count) { |
| 5416 for (int i = 0; i < count; ++i) { |
| 5417 Pop(); |
| 5315 } | 5418 } |
| 5316 } | 5419 } |
| 5317 | 5420 |
| 5318 | 5421 |
| 5319 HEnvironment* HEnvironment::Copy() const { | 5422 HEnvironment* HEnvironment::Copy() const { |
| 5320 return new HEnvironment(this); | 5423 return new HEnvironment(this); |
| 5321 } | 5424 } |
| 5322 | 5425 |
| 5323 | 5426 |
| 5324 HEnvironment* HEnvironment::CopyWithoutHistory() const { | 5427 HEnvironment* HEnvironment::CopyWithoutHistory() const { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5369 for (int i = 0; i < local_count; ++i) { | 5472 for (int i = 0; i < local_count; ++i) { |
| 5370 inner->SetValueAt(local_base + i, undefined); | 5473 inner->SetValueAt(local_base + i, undefined); |
| 5371 } | 5474 } |
| 5372 | 5475 |
| 5373 inner->set_ast_id(function->id()); | 5476 inner->set_ast_id(function->id()); |
| 5374 return inner; | 5477 return inner; |
| 5375 } | 5478 } |
| 5376 | 5479 |
| 5377 | 5480 |
| 5378 void HEnvironment::PrintTo(StringStream* stream) { | 5481 void HEnvironment::PrintTo(StringStream* stream) { |
| 5379 for (int i = 0; i < total_count(); i++) { | 5482 for (int i = 0; i < length(); i++) { |
| 5380 if (i == 0) stream->Add("parameters\n"); | 5483 if (i == 0) stream->Add("parameters\n"); |
| 5381 if (i == parameter_count()) stream->Add("locals\n"); | 5484 if (i == parameter_count()) stream->Add("locals\n"); |
| 5382 if (i == parameter_count() + local_count()) stream->Add("expressions"); | 5485 if (i == parameter_count() + local_count()) stream->Add("expressions"); |
| 5383 HValue* val = values_.at(i); | 5486 HValue* val = values_.at(i); |
| 5384 stream->Add("%d: ", i); | 5487 stream->Add("%d: ", i); |
| 5385 if (val != NULL) { | 5488 if (val != NULL) { |
| 5386 val->PrintNameTo(stream); | 5489 val->PrintNameTo(stream); |
| 5387 } else { | 5490 } else { |
| 5388 stream->Add("NULL"); | 5491 stream->Add("NULL"); |
| 5389 } | 5492 } |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5607 PrintF("Timing results:\n"); | 5710 PrintF("Timing results:\n"); |
| 5608 int64_t sum = 0; | 5711 int64_t sum = 0; |
| 5609 for (int i = 0; i < timing_.length(); ++i) { | 5712 for (int i = 0; i < timing_.length(); ++i) { |
| 5610 sum += timing_[i]; | 5713 sum += timing_[i]; |
| 5611 } | 5714 } |
| 5612 | 5715 |
| 5613 for (int i = 0; i < names_.length(); ++i) { | 5716 for (int i = 0; i < names_.length(); ++i) { |
| 5614 PrintF("%30s", names_[i]); | 5717 PrintF("%30s", names_[i]); |
| 5615 double ms = static_cast<double>(timing_[i]) / 1000; | 5718 double ms = static_cast<double>(timing_[i]) / 1000; |
| 5616 double percent = static_cast<double>(timing_[i]) * 100 / sum; | 5719 double percent = static_cast<double>(timing_[i]) * 100 / sum; |
| 5617 PrintF(" - %0.3f ms / %0.3f %% \n", ms, percent); | 5720 PrintF(" - %7.3f ms / %4.1f %% ", ms, percent); |
| 5721 |
| 5722 unsigned size = sizes_[i]; |
| 5723 double size_percent = static_cast<double>(size) * 100 / total_size_; |
| 5724 PrintF(" %8u bytes / %4.1f %%\n", size, size_percent); |
| 5618 } | 5725 } |
| 5619 PrintF("%30s - %0.3f ms \n", "Sum", static_cast<double>(sum) / 1000); | 5726 PrintF("%30s - %7.3f ms %8u bytes\n", "Sum", |
| 5727 static_cast<double>(sum) / 1000, |
| 5728 total_size_); |
| 5620 PrintF("---------------------------------------------------------------\n"); | 5729 PrintF("---------------------------------------------------------------\n"); |
| 5621 PrintF("%30s - %0.3f ms (%0.1f times slower than full code gen)\n", | 5730 PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n", |
| 5622 "Total", | 5731 "Total", |
| 5623 static_cast<double>(total_) / 1000, | 5732 static_cast<double>(total_) / 1000, |
| 5624 static_cast<double>(total_) / full_code_gen_); | 5733 static_cast<double>(total_) / full_code_gen_); |
| 5625 } | 5734 } |
| 5626 | 5735 |
| 5627 | 5736 |
| 5628 void HStatistics::SaveTiming(const char* name, int64_t ticks) { | 5737 void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) { |
| 5629 if (name == HPhase::kFullCodeGen) { | 5738 if (name == HPhase::kFullCodeGen) { |
| 5630 full_code_gen_ += ticks; | 5739 full_code_gen_ += ticks; |
| 5631 } else if (name == HPhase::kTotal) { | 5740 } else if (name == HPhase::kTotal) { |
| 5632 total_ += ticks; | 5741 total_ += ticks; |
| 5633 } else { | 5742 } else { |
| 5743 total_size_ += size; |
| 5634 for (int i = 0; i < names_.length(); ++i) { | 5744 for (int i = 0; i < names_.length(); ++i) { |
| 5635 if (names_[i] == name) { | 5745 if (names_[i] == name) { |
| 5636 timing_[i] += ticks; | 5746 timing_[i] += ticks; |
| 5747 sizes_[i] += size; |
| 5637 return; | 5748 return; |
| 5638 } | 5749 } |
| 5639 } | 5750 } |
| 5640 names_.Add(name); | 5751 names_.Add(name); |
| 5641 timing_.Add(ticks); | 5752 timing_.Add(ticks); |
| 5753 sizes_.Add(size); |
| 5642 } | 5754 } |
| 5643 } | 5755 } |
| 5644 | 5756 |
| 5645 | 5757 |
| 5646 const char* const HPhase::kFullCodeGen = "Full code generator"; | 5758 const char* const HPhase::kFullCodeGen = "Full code generator"; |
| 5647 const char* const HPhase::kTotal = "Total"; | 5759 const char* const HPhase::kTotal = "Total"; |
| 5648 | 5760 |
| 5649 | 5761 |
| 5650 void HPhase::Begin(const char* name, | 5762 void HPhase::Begin(const char* name, |
| 5651 HGraph* graph, | 5763 HGraph* graph, |
| 5652 LChunk* chunk, | 5764 LChunk* chunk, |
| 5653 LAllocator* allocator) { | 5765 LAllocator* allocator) { |
| 5654 name_ = name; | 5766 name_ = name; |
| 5655 graph_ = graph; | 5767 graph_ = graph; |
| 5656 chunk_ = chunk; | 5768 chunk_ = chunk; |
| 5657 allocator_ = allocator; | 5769 allocator_ = allocator; |
| 5658 if (allocator != NULL && chunk_ == NULL) { | 5770 if (allocator != NULL && chunk_ == NULL) { |
| 5659 chunk_ = allocator->chunk(); | 5771 chunk_ = allocator->chunk(); |
| 5660 } | 5772 } |
| 5661 if (FLAG_time_hydrogen) start_ = OS::Ticks(); | 5773 if (FLAG_time_hydrogen) start_ = OS::Ticks(); |
| 5774 start_allocation_size_ = Zone::allocation_size_; |
| 5662 } | 5775 } |
| 5663 | 5776 |
| 5664 | 5777 |
| 5665 void HPhase::End() const { | 5778 void HPhase::End() const { |
| 5666 if (FLAG_time_hydrogen) { | 5779 if (FLAG_time_hydrogen) { |
| 5667 int64_t end = OS::Ticks(); | 5780 int64_t end = OS::Ticks(); |
| 5668 HStatistics::Instance()->SaveTiming(name_, end - start_); | 5781 unsigned size = Zone::allocation_size_ - start_allocation_size_; |
| 5782 HStatistics::Instance()->SaveTiming(name_, end - start_, size); |
| 5669 } | 5783 } |
| 5670 | 5784 |
| 5671 if (FLAG_trace_hydrogen) { | 5785 if (FLAG_trace_hydrogen) { |
| 5672 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_); | 5786 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_); |
| 5673 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_); | 5787 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_); |
| 5674 if (allocator_ != NULL) { | 5788 if (allocator_ != NULL) { |
| 5675 HTracer::Instance()->TraceLiveRanges(name_, allocator_); | 5789 HTracer::Instance()->TraceLiveRanges(name_, allocator_); |
| 5676 } | 5790 } |
| 5677 } | 5791 } |
| 5678 | 5792 |
| 5679 #ifdef DEBUG | 5793 #ifdef DEBUG |
| 5680 if (graph_ != NULL) graph_->Verify(); | 5794 if (graph_ != NULL) graph_->Verify(); |
| 5681 if (chunk_ != NULL) chunk_->Verify(); | |
| 5682 if (allocator_ != NULL) allocator_->Verify(); | 5795 if (allocator_ != NULL) allocator_->Verify(); |
| 5683 #endif | 5796 #endif |
| 5684 } | 5797 } |
| 5685 | 5798 |
| 5686 } } // namespace v8::internal | 5799 } } // namespace v8::internal |
| OLD | NEW |