diff options
Diffstat (limited to 'deps/v8/src/hydrogen.cc')
-rw-r--r-- | deps/v8/src/hydrogen.cc | 976 |
1 files changed, 546 insertions, 430 deletions
diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 75344bb513..d1e5b51a5e 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -133,7 +133,8 @@ HDeoptimize* HBasicBlock::CreateDeoptimize( } -HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id) { +HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id, + RemovableSimulate removable) { ASSERT(HasEnvironment()); HEnvironment* environment = last_environment(); ASSERT(ast_id.IsNone() || @@ -142,8 +143,12 @@ HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id) { int push_count = environment->push_count(); int pop_count = environment->pop_count(); - HSimulate* instr = new(zone()) HSimulate(ast_id, pop_count, zone()); - for (int i = push_count - 1; i >= 0; --i) { + HSimulate* instr = + new(zone()) HSimulate(ast_id, pop_count, zone(), removable); + // Order of pushed values: newest (top of stack) first. This allows + // HSimulate::MergeInto() to easily append additional pushed values + // that are older (from further down the stack). + for (int i = 0; i < push_count; ++i) { instr->AddPushedValue(environment->ExpressionStackAt(i)); } for (int i = 0; i < environment->assigned_variables()->length(); ++i) { @@ -168,10 +173,9 @@ void HBasicBlock::Finish(HControlInstruction* end) { void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) { bool drop_extra = state != NULL && state->inlining_kind() == DROP_EXTRA_ON_RETURN; - bool arguments_pushed = state != NULL && state->arguments_pushed(); if (block->IsInlineReturnTarget()) { - AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); + AddInstruction(new(zone()) HLeaveInlined()); last_environment_ = last_environment()->DiscardInlined(drop_extra); } @@ -185,11 +189,10 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value, FunctionState* state) { HBasicBlock* target = state->function_return(); bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; - bool arguments_pushed = state->arguments_pushed(); ASSERT(target->IsInlineReturnTarget()); ASSERT(return_value != NULL); - AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); + AddInstruction(new(zone()) HLeaveInlined()); last_environment_ = last_environment()->DiscardInlined(drop_extra); last_environment()->Push(return_value); AddSimulate(BailoutId::None()); @@ -1293,7 +1296,7 @@ void HRangeAnalysis::Analyze(HBasicBlock* block) { void HRangeAnalysis::InferControlFlowRange(HCompareIDAndBranch* test, HBasicBlock* dest) { ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest)); - if (test->GetInputRepresentation().IsInteger32()) { + if (test->representation().IsInteger32()) { Token::Value op = test->token(); if (test->SecondSuccessor() == dest) { op = Token::NegateCompareOp(op); @@ -1950,52 +1953,6 @@ void HGlobalValueNumberer::ProcessLoopBlock( if (can_hoist && !graph()->use_optimistic_licm()) { can_hoist = block->IsLoopSuccessorDominator(); } - if (instr->IsTransitionElementsKind()) { - // It's possible to hoist transitions out of a loop as long as the - // hoisting wouldn't move the transition past an instruction that has a - // DependsOn flag for anything it changes. - GVNFlagSet hoist_depends_blockers = - HValue::ConvertChangesToDependsFlags(instr->ChangesFlags()); - - // In addition, the transition must not be hoisted above elements kind - // changes, or if the transition is destructive to the elements buffer, - // changes to array pointer or array contents. - GVNFlagSet hoist_change_blockers; - hoist_change_blockers.Add(kChangesElementsKind); - HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr); - if (trans->original_map()->has_fast_double_elements()) { - hoist_change_blockers.Add(kChangesElementsPointer); - hoist_change_blockers.Add(kChangesDoubleArrayElements); - } - if (trans->transitioned_map()->has_fast_double_elements()) { - hoist_change_blockers.Add(kChangesElementsPointer); - hoist_change_blockers.Add(kChangesArrayElements); - } - if (FLAG_trace_gvn) { - GVNFlagSet hoist_blockers = hoist_depends_blockers; - hoist_blockers.Add(hoist_change_blockers); - GVNFlagSet first_time = *first_time_changes; - first_time.Add(*first_time_depends); - TRACE_GVN_4("Checking dependencies on HTransitionElementsKind " - "%d (%s) hoist blockers: %s; " - "first-time accumulated: %s\n", - instr->id(), - instr->Mnemonic(), - *GetGVNFlagsString(hoist_blockers), - *GetGVNFlagsString(first_time)); - } - // It's possible to hoist transition from the current loop loop only if - // they dominate all of the successor blocks in the same loop and there - // are not any instructions that have Changes/DependsOn that intervene - // between it and the beginning of the loop header. - bool in_nested_loop = block != loop_header && - ((block->parent_loop_header() != loop_header) || - block->IsLoopHeader()); - can_hoist = !in_nested_loop && - block->IsLoopSuccessorDominator() && - !first_time_depends->ContainsAnyOf(hoist_depends_blockers) && - !first_time_changes->ContainsAnyOf(hoist_change_blockers); - } if (can_hoist) { bool inputs_loop_invariant = true; @@ -2287,32 +2244,8 @@ void HGlobalValueNumberer::AnalyzeGraph() { } -class HInferRepresentation BASE_EMBEDDED { - public: - explicit HInferRepresentation(HGraph* graph) - : graph_(graph), - worklist_(8, graph->zone()), - in_worklist_(graph->GetMaximumValueID(), graph->zone()) { } - - void Analyze(); - - private: - Representation TryChange(HValue* current); - void AddToWorklist(HValue* current); - void InferBasedOnInputs(HValue* current); - void AddDependantsToWorklist(HValue* current); - void InferBasedOnUses(HValue* current); - - Zone* zone() const { return graph_->zone(); } - - HGraph* graph_; - ZoneList<HValue*> worklist_; - BitVector in_worklist_; -}; - - void HInferRepresentation::AddToWorklist(HValue* current) { - if (current->representation().IsSpecialization()) return; + if (current->representation().IsTagged()) return; if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return; if (in_worklist_.Contains(current->id())) return; worklist_.Add(current, zone()); @@ -2320,105 +2253,6 @@ void HInferRepresentation::AddToWorklist(HValue* current) { } -// This method tries to specialize the representation type of the value -// given as a parameter. The value is asked to infer its representation type -// based on its inputs. If the inferred type is more specialized, then this -// becomes the new representation type of the node. -void HInferRepresentation::InferBasedOnInputs(HValue* current) { - Representation r = current->representation(); - if (r.IsSpecialization()) return; - ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation)); - Representation inferred = current->InferredRepresentation(); - if (inferred.IsSpecialization()) { - if (FLAG_trace_representation) { - PrintF("Changing #%d representation %s -> %s based on inputs\n", - current->id(), - r.Mnemonic(), - inferred.Mnemonic()); - } - current->ChangeRepresentation(inferred); - AddDependantsToWorklist(current); - } -} - - -void HInferRepresentation::AddDependantsToWorklist(HValue* value) { - for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) { - AddToWorklist(it.value()); - } - for (int i = 0; i < value->OperandCount(); ++i) { - AddToWorklist(value->OperandAt(i)); - } -} - - -// This method calculates whether specializing the representation of the value -// given as the parameter has a benefit in terms of less necessary type -// conversions. If there is a benefit, then the representation of the value is -// specialized. -void HInferRepresentation::InferBasedOnUses(HValue* value) { - Representation r = value->representation(); - if (r.IsSpecialization() || value->HasNoUses()) return; - ASSERT(value->CheckFlag(HValue::kFlexibleRepresentation)); - Representation new_rep = TryChange(value); - if (!new_rep.IsNone()) { - if (!value->representation().Equals(new_rep)) { - if (FLAG_trace_representation) { - PrintF("Changing #%d representation %s -> %s based on uses\n", - value->id(), - r.Mnemonic(), - new_rep.Mnemonic()); - } - value->ChangeRepresentation(new_rep); - AddDependantsToWorklist(value); - } - } -} - - -Representation HInferRepresentation::TryChange(HValue* value) { - // Array of use counts for each representation. - int use_count[Representation::kNumRepresentations] = { 0 }; - - for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) { - HValue* use = it.value(); - Representation rep = use->ObservedInputRepresentation(it.index()); - if (rep.IsNone()) continue; - if (FLAG_trace_representation) { - PrintF("%d %s is used by %d %s as %s\n", - value->id(), - value->Mnemonic(), - use->id(), - use->Mnemonic(), - rep.Mnemonic()); - } - if (use->IsPhi()) HPhi::cast(use)->AddIndirectUsesTo(&use_count[0]); - use_count[rep.kind()] += use->LoopWeight(); - } - int tagged_count = use_count[Representation::kTagged]; - int double_count = use_count[Representation::kDouble]; - int int32_count = use_count[Representation::kInteger32]; - int non_tagged_count = double_count + int32_count; - - // If a non-loop phi has tagged uses, don't convert it to untagged. - if (value->IsPhi() && !value->block()->IsLoopHeader() && tagged_count > 0) { - return Representation::None(); - } - - // Prefer unboxing over boxing, the latter is more expensive. - if (tagged_count > non_tagged_count) return Representation::None(); - - // Prefer Integer32 over Double, if possible. - if (int32_count > 0 && value->IsConvertibleToInteger()) { - return Representation::Integer32(); - } - - if (double_count > 0) return Representation::Double(); - - return Representation::None(); -} - - void HInferRepresentation::Analyze() { HPhase phase("H_Infer representations", graph_); @@ -2469,7 +2303,6 @@ void HInferRepresentation::Analyze() { it.Advance()) { HPhi* phi = phi_list->at(it.Current()); phi->set_is_convertible_to_integer(false); - phi->ResetInteger32Uses(); } } @@ -2505,8 +2338,74 @@ void HInferRepresentation::Analyze() { while (!worklist_.is_empty()) { HValue* current = worklist_.RemoveLast(); in_worklist_.Remove(current->id()); - InferBasedOnInputs(current); - InferBasedOnUses(current); + current->InferRepresentation(this); + } + + // Lastly: any instruction that we don't have representation information + // for defaults to Tagged. + for (int i = 0; i < graph_->blocks()->length(); ++i) { + HBasicBlock* block = graph_->blocks()->at(i); + const ZoneList<HPhi*>* phis = block->phis(); + for (int j = 0; j < phis->length(); ++j) { + HPhi* phi = phis->at(j); + if (phi->representation().IsNone()) { + phi->ChangeRepresentation(Representation::Tagged()); + } + } + for (HInstruction* current = block->first(); + current != NULL; current = current->next()) { + if (current->representation().IsNone() && + current->CheckFlag(HInstruction::kFlexibleRepresentation)) { + current->ChangeRepresentation(Representation::Tagged()); + } + } + } +} + + +void HGraph::MergeRemovableSimulates() { + for (int i = 0; i < blocks()->length(); ++i) { + HBasicBlock* block = blocks()->at(i); + // Always reset the folding candidate at the start of a block. + HSimulate* folding_candidate = NULL; + // Nasty heuristic: Never remove the first simulate in a block. This + // just so happens to have a beneficial effect on register allocation. + bool first = true; + for (HInstruction* current = block->first(); + current != NULL; current = current->next()) { + if (current->IsLeaveInlined()) { + // Never fold simulates from inlined environments into simulates + // in the outer environment. + // (Before each HEnterInlined, there is a non-foldable HSimulate + // anyway, so we get the barrier in the other direction for free.) + if (folding_candidate != NULL) { + folding_candidate->DeleteAndReplaceWith(NULL); + } + folding_candidate = NULL; + continue; + } + // If we have an HSimulate and a candidate, perform the folding. + if (!current->IsSimulate()) continue; + if (first) { + first = false; + continue; + } + HSimulate* current_simulate = HSimulate::cast(current); + if (folding_candidate != NULL) { + folding_candidate->MergeInto(current_simulate); + folding_candidate->DeleteAndReplaceWith(NULL); + folding_candidate = NULL; + } + // Check if the current simulate is a candidate for folding. + if (current_simulate->previous()->HasObservableSideEffects() && + !current_simulate->next()->IsSimulate()) { + continue; + } + if (!current_simulate->is_candidate_for_removal()) { + continue; + } + folding_candidate = current_simulate; + } } } @@ -2601,7 +2500,6 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value, } else { next = HInstruction::cast(use_value); } - // For constants we try to make the representation change at compile // time. When a representation change is not possible without loss of // information we treat constants like normal instructions and insert the @@ -2613,7 +2511,7 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value, if (value->IsConstant()) { HConstant* constant = HConstant::cast(value); // Try to create a new copy of the constant with the new representation. - new_value = is_truncating + new_value = (is_truncating && to.IsInteger32()) ? constant->CopyToTruncatedInt32(zone()) : constant->CopyToRepresentation(to, zone()); } @@ -2673,9 +2571,23 @@ void HGraph::InsertRepresentationChanges() { for (int i = 0; i < phi_list()->length(); i++) { HPhi* phi = phi_list()->at(i); if (!phi->CheckFlag(HValue::kTruncatingToInt32)) continue; - if (!phi->CheckUsesForFlag(HValue::kTruncatingToInt32)) { - phi->ClearFlag(HValue::kTruncatingToInt32); - change = true; + for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) { + // If a Phi is used as a non-truncating int32 or as a double, + // clear its "truncating" flag. + HValue* use = it.value(); + Representation input_representation = + use->RequiredInputRepresentation(it.index()); + if ((input_representation.IsInteger32() && + !use->CheckFlag(HValue::kTruncatingToInt32)) || + input_representation.IsDouble()) { + if (FLAG_trace_representation) { + PrintF("#%d Phi is not truncating because of #%d %s\n", + phi->id(), it.value()->id(), it.value()->Mnemonic()); + } + phi->ClearFlag(HValue::kTruncatingToInt32); + change = true; + break; + } } } } @@ -2690,8 +2602,9 @@ void HGraph::InsertRepresentationChanges() { // Process normal instructions. HInstruction* current = blocks_[i]->first(); while (current != NULL) { + HInstruction* next = current->next(); InsertRepresentationChangesForValue(current); - current = current->next(); + current = next; } } } @@ -2763,17 +2676,18 @@ bool Uint32Analysis::IsSafeUint32Use(HValue* val, HValue* use) { } else if (use->IsChange() || use->IsSimulate()) { // Conversions and deoptimization have special support for unt32. return true; - } else if (use->IsStoreKeyedSpecializedArrayElement()) { - // Storing a value into an external integer array is a bit level operation. - HStoreKeyedSpecializedArrayElement* store = - HStoreKeyedSpecializedArrayElement::cast(use); - - if (store->value() == val) { - // Clamping or a conversion to double should have beed inserted. - ASSERT(store->elements_kind() != EXTERNAL_PIXEL_ELEMENTS); - ASSERT(store->elements_kind() != EXTERNAL_FLOAT_ELEMENTS); - ASSERT(store->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS); - return true; + } else if (use->IsStoreKeyed()) { + HStoreKeyed* store = HStoreKeyed::cast(use); + if (store->is_external()) { + // Storing a value into an external integer array is a bit level + // operation. + if (store->value() == val) { + // Clamping or a conversion to double should have beed inserted. + ASSERT(store->elements_kind() != EXTERNAL_PIXEL_ELEMENTS); + ASSERT(store->elements_kind() != EXTERNAL_FLOAT_ELEMENTS); + ASSERT(store->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS); + return true; + } } } @@ -3085,7 +2999,9 @@ void TestContext::ReturnValue(HValue* value) { void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { ASSERT(!instr->IsControlInstruction()); owner()->AddInstruction(instr); - if (instr->HasObservableSideEffects()) owner()->AddSimulate(ast_id); + if (instr->HasObservableSideEffects()) { + owner()->AddSimulate(ast_id, REMOVABLE_SIMULATE); + } } @@ -3109,7 +3025,9 @@ void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { } owner()->AddInstruction(instr); owner()->Push(instr); - if (instr->HasObservableSideEffects()) owner()->AddSimulate(ast_id); + if (instr->HasObservableSideEffects()) { + owner()->AddSimulate(ast_id, REMOVABLE_SIMULATE); + } } @@ -3141,7 +3059,7 @@ void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { // this one isn't actually needed (and wouldn't work if it were targeted). if (instr->HasObservableSideEffects()) { builder->Push(instr); - builder->AddSimulate(ast_id); + builder->AddSimulate(ast_id, REMOVABLE_SIMULATE); builder->Pop(); } BuildBranch(instr); @@ -3319,9 +3237,8 @@ HGraph* HGraphBuilder::CreateGraph() { // optimization. Disable optimistic LICM in that case. Handle<Code> unoptimized_code(info()->shared_info()->code()); ASSERT(unoptimized_code->kind() == Code::FUNCTION); - Handle<Object> maybe_type_info(unoptimized_code->type_feedback_info()); Handle<TypeFeedbackInfo> type_info( - Handle<TypeFeedbackInfo>::cast(maybe_type_info)); + TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); int checksum = type_info->own_type_change_checksum(); int composite_checksum = graph()->update_type_change_checksum(checksum); graph()->set_use_optimistic_licm( @@ -3368,6 +3285,11 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { HInferRepresentation rep(this); rep.Analyze(); + // Remove HSimulate instructions that have turned out not to be needed + // after all by folding them into the following HSimulate. + // This must happen after inferring representations. + MergeRemovableSimulates(); + MarkDeoptimizeOnUndefined(); InsertRepresentationChanges(); @@ -3406,6 +3328,7 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { EliminateRedundantBoundsChecks(); DehoistSimpleArrayIndexComputations(); + if (FLAG_dead_code_elimination) DeadCodeElimination(); return true; } @@ -3432,6 +3355,8 @@ class BoundsCheckKey : public ZoneObject { static BoundsCheckKey* Create(Zone* zone, HBoundsCheck* check, int32_t* offset) { + if (!check->index()->representation().IsInteger32()) return NULL; + HValue* index_base = NULL; HConstant* constant = NULL; bool is_sub = false; @@ -3613,7 +3538,10 @@ class BoundsCheckBbData: public ZoneObject { HConstant(new_offset, Representation::Integer32()); if (*add == NULL) { new_constant->InsertBefore(check); - *add = new(BasicBlock()->zone()) HAdd(NULL, + // Because of the bounds checks elimination algorithm, the index is always + // an HAdd or an HSub here, so we can safely cast to an HBinaryOperation. + HValue* context = HBinaryOperation::cast(check->index())->context(); + *add = new(BasicBlock()->zone()) HAdd(context, original_value, new_constant); (*add)->AssumeRepresentation(representation); @@ -3682,6 +3610,7 @@ void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb, int32_t offset; BoundsCheckKey* key = BoundsCheckKey::Create(zone(), check, &offset); + if (key == NULL) continue; BoundsCheckBbData** data_p = table->LookupOrInsert(key, zone()); BoundsCheckBbData* data = *data_p; if (data == NULL) { @@ -3743,6 +3672,7 @@ void HGraph::EliminateRedundantBoundsChecks() { static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { HValue* index = array_operation->GetKey(); + if (!index->representation().IsInteger32()) return; HConstant* constant; HValue* subexpression; @@ -3797,27 +3727,11 @@ void HGraph::DehoistSimpleArrayIndexComputations() { instr != NULL; instr = instr->next()) { ArrayInstructionInterface* array_instruction = NULL; - if (instr->IsLoadKeyedFastElement()) { - HLoadKeyedFastElement* op = HLoadKeyedFastElement::cast(instr); - array_instruction = static_cast<ArrayInstructionInterface*>(op); - } else if (instr->IsLoadKeyedFastDoubleElement()) { - HLoadKeyedFastDoubleElement* op = - HLoadKeyedFastDoubleElement::cast(instr); + if (instr->IsLoadKeyed()) { + HLoadKeyed* op = HLoadKeyed::cast(instr); array_instruction = static_cast<ArrayInstructionInterface*>(op); - } else if (instr->IsLoadKeyedSpecializedArrayElement()) { - HLoadKeyedSpecializedArrayElement* op = - HLoadKeyedSpecializedArrayElement::cast(instr); - array_instruction = static_cast<ArrayInstructionInterface*>(op); - } else if (instr->IsStoreKeyedFastElement()) { - HStoreKeyedFastElement* op = HStoreKeyedFastElement::cast(instr); - array_instruction = static_cast<ArrayInstructionInterface*>(op); - } else if (instr->IsStoreKeyedFastDoubleElement()) { - HStoreKeyedFastDoubleElement* op = - HStoreKeyedFastDoubleElement::cast(instr); - array_instruction = static_cast<ArrayInstructionInterface*>(op); - } else if (instr->IsStoreKeyedSpecializedArrayElement()) { - HStoreKeyedSpecializedArrayElement* op = - HStoreKeyedSpecializedArrayElement::cast(instr); + } else if (instr->IsStoreKeyed()) { + HStoreKeyed* op = HStoreKeyed::cast(instr); array_instruction = static_cast<ArrayInstructionInterface*>(op); } else { continue; @@ -3828,6 +3742,36 @@ void HGraph::DehoistSimpleArrayIndexComputations() { } +void HGraph::DeadCodeElimination() { + HPhase phase("H_Dead code elimination", this); + ZoneList<HInstruction*> worklist(blocks_.length(), zone()); + for (int i = 0; i < blocks()->length(); ++i) { + for (HInstruction* instr = blocks()->at(i)->first(); + instr != NULL; + instr = instr->next()) { + if (instr->IsDead()) worklist.Add(instr, zone()); + } + } + + while (!worklist.is_empty()) { + HInstruction* instr = worklist.RemoveLast(); + if (FLAG_trace_dead_code_elimination) { + HeapStringAllocator allocator; + StringStream stream(&allocator); + instr->PrintNameTo(&stream); + stream.Add(" = "); + instr->PrintTo(&stream); + PrintF("[removing dead instruction %s]\n", *stream.ToCString()); + } + instr->DeleteAndReplaceWith(NULL); + for (int i = 0; i < instr->OperandCount(); ++i) { + HValue* operand = instr->OperandAt(i); + if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone()); + } + } +} + + HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { ASSERT(current_block() != NULL); current_block()->AddInstruction(instr); @@ -3835,9 +3779,9 @@ HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { } -void HGraphBuilder::AddSimulate(BailoutId ast_id) { +void HGraphBuilder::AddSimulate(BailoutId ast_id, RemovableSimulate removable) { ASSERT(current_block() != NULL); - current_block()->AddSimulate(ast_id); + current_block()->AddSimulate(ast_id, removable); } @@ -4194,7 +4138,7 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { !clause->label()->IsStringLiteral()) || (switch_type == SMI_SWITCH && !clause->label()->IsSmiLiteral())) { - return Bailout("SwitchStatemnt: mixed label types are not supported"); + return Bailout("SwitchStatement: mixed label types are not supported"); } } @@ -4248,12 +4192,13 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { new(zone()) HCompareIDAndBranch(tag_value, label_value, Token::EQ_STRICT); - compare_->SetInputRepresentation(Representation::Integer32()); + compare_->set_observed_input_representation( + Representation::Integer32(), Representation::Integer32()); compare = compare_; } else { compare = new(zone()) HStringCompareAndBranch(context, tag_value, - label_value, - Token::EQ_STRICT); + label_value, + Token::EQ_STRICT); } compare->SetSuccessorAt(0, body_block); @@ -4612,7 +4557,8 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { // Check that we still have more keys. HCompareIDAndBranch* compare_index = new(zone()) HCompareIDAndBranch(index, limit, Token::LT); - compare_index->SetInputRepresentation(Representation::Integer32()); + compare_index->set_observed_input_representation( + Representation::Integer32(), Representation::Integer32()); HBasicBlock* loop_body = graph()->CreateBasicBlock(); HBasicBlock* loop_successor = graph()->CreateBasicBlock(); @@ -4627,10 +4573,11 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { set_current_block(loop_body); HValue* key = AddInstruction( - new(zone()) HLoadKeyedFastElement( + new(zone()) HLoadKeyed( environment()->ExpressionStackAt(2), // Enum cache. environment()->ExpressionStackAt(0), // Iteration index. - environment()->ExpressionStackAt(0))); + environment()->ExpressionStackAt(0), + FAST_ELEMENTS)); // Check if the expected map still matches that of the enumerable. // If not just deoptimize. @@ -4886,7 +4833,7 @@ void HGraphBuilder::VisitLiteral(Literal* expr) { ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); HConstant* instr = - new(zone()) HConstant(expr->handle(), Representation::Tagged()); + new(zone()) HConstant(expr->handle(), Representation::None()); return ast_context()->ReturnInstruction(instr, expr->id()); } @@ -5123,7 +5070,9 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { map)); } AddInstruction(store); - if (store->HasObservableSideEffects()) AddSimulate(key->id()); + if (store->HasObservableSideEffects()) { + AddSimulate(key->id(), REMOVABLE_SIMULATE); + } } else { CHECK_ALIVE(VisitForEffect(value)); } @@ -5235,18 +5184,14 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { // Fall through. case FAST_ELEMENTS: case FAST_HOLEY_ELEMENTS: - AddInstruction(new(zone()) HStoreKeyedFastElement( + case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + AddInstruction(new(zone()) HStoreKeyed( elements, key, value, boilerplate_elements_kind)); break; - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements, - key, - value)); - break; default: UNREACHABLE(); break; @@ -5291,18 +5236,19 @@ static int ComputeLoadStoreFieldIndex(Handle<Map> type, } +void HGraphBuilder::AddCheckMapsWithTransitions(HValue* object, + Handle<Map> map) { + AddInstruction(new(zone()) HCheckNonSmi(object)); + AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone())); +} + + HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object, Handle<String> name, HValue* value, Handle<Map> map, - LookupResult* lookup, - bool smi_and_map_check) { + LookupResult* lookup) { ASSERT(lookup->IsFound()); - if (smi_and_map_check) { - AddInstruction(new(zone()) HCheckNonSmi(object)); - AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone())); - } - // If the property does not exist yet, we have to check that it wasn't made // readonly or turned into a setter by some meanwhile modifications on the // prototype chain. @@ -5371,7 +5317,7 @@ HInstruction* HGraphBuilder::BuildCallSetter(HValue* object, Handle<Map> map, Handle<JSFunction> setter, Handle<JSObject> holder) { - AddCheckConstantFunction(holder, object, map, true); + AddCheckConstantFunction(holder, object, map); AddInstruction(new(zone()) HPushArgument(object)); AddInstruction(new(zone()) HPushArgument(value)); return new(zone()) HCallConstantFunction(setter, 2); @@ -5385,8 +5331,8 @@ HInstruction* HGraphBuilder::BuildStoreNamedMonomorphic(HValue* object, // Handle a store to a known field. LookupResult lookup(isolate()); if (ComputeLoadStoreField(map, name, &lookup, true)) { - // true = needs smi and map check. - return BuildStoreNamedField(object, name, value, map, &lookup, true); + AddCheckMapsWithTransitions(object, map); + return BuildStoreNamedField(object, name, value, map, &lookup); } // No luck, do a generic store. @@ -5434,7 +5380,7 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, HInstruction* instr; if (count == types->length() && is_monomorphic_field) { AddInstruction(new(zone()) HCheckMaps(object, types, zone())); - instr = BuildLoadNamedField(object, map, &lookup, false); + instr = BuildLoadNamedField(object, map, &lookup); } else { HValue* context = environment()->LookupContext(); instr = new(zone()) HLoadNamedFieldPolymorphic(context, @@ -5477,7 +5423,7 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, set_current_block(if_true); HInstruction* instr; CHECK_ALIVE(instr = - BuildStoreNamedField(object, name, value, map, &lookup, false)); + BuildStoreNamedField(object, name, value, map, &lookup)); instr->set_position(expr->position()); // Goto will add the HSimulate for the store. AddInstruction(instr); @@ -5507,10 +5453,10 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, // unoptimized code). if (instr->HasObservableSideEffects()) { if (ast_context()->IsEffect()) { - AddSimulate(expr->id()); + AddSimulate(expr->id(), REMOVABLE_SIMULATE); } else { Push(value); - AddSimulate(expr->id()); + AddSimulate(expr->id(), REMOVABLE_SIMULATE); Drop(1); } } @@ -5553,7 +5499,7 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { Handle<JSFunction> setter; Handle<JSObject> holder; if (LookupSetter(map, name, &setter, &holder)) { - AddCheckConstantFunction(holder, object, map, true); + AddCheckConstantFunction(holder, object, map); if (FLAG_inline_accessors && TryInlineSetter(setter, expr, value)) { return; } @@ -5580,7 +5526,9 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { Push(value); instr->set_position(expr->position()); AddInstruction(instr); - if (instr->HasObservableSideEffects()) AddSimulate(expr->AssignmentId()); + if (instr->HasObservableSideEffects()) { + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); + } return ast_context()->ReturnValue(Pop()); } else { @@ -5597,7 +5545,7 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { &has_side_effects); Push(value); ASSERT(has_side_effects); // Stores always have side effects. - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); return ast_context()->ReturnValue(Pop()); } } @@ -5619,7 +5567,9 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails()); instr->set_position(position); AddInstruction(instr); - if (instr->HasObservableSideEffects()) AddSimulate(ast_id); + if (instr->HasObservableSideEffects()) { + AddSimulate(ast_id, REMOVABLE_SIMULATE); + } } else { HValue* context = environment()->LookupContext(); HGlobalObject* global_object = new(zone()) HGlobalObject(context); @@ -5633,7 +5583,7 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, instr->set_position(position); AddInstruction(instr); ASSERT(instr->HasObservableSideEffects()); - if (instr->HasObservableSideEffects()) AddSimulate(ast_id); + AddSimulate(ast_id, REMOVABLE_SIMULATE); } } @@ -5710,7 +5660,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { new(zone()) HStoreContextSlot(context, var->index(), mode, Top()); AddInstruction(instr); if (instr->HasObservableSideEffects()) { - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); } break; } @@ -5750,7 +5700,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { load = BuildLoadNamedGeneric(object, name, prop); } PushAndAdd(load); - if (load->HasObservableSideEffects()) AddSimulate(prop->LoadId()); + if (load->HasObservableSideEffects()) { + AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); + } CHECK_ALIVE(VisitForValue(expr->value())); HValue* right = Pop(); @@ -5758,7 +5710,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { HInstruction* instr = BuildBinaryOperation(operation, left, right); PushAndAdd(instr); - if (instr->HasObservableSideEffects()) AddSimulate(operation->id()); + if (instr->HasObservableSideEffects()) { + AddSimulate(operation->id(), REMOVABLE_SIMULATE); + } HInstruction* store; if (!monomorphic) { @@ -5780,7 +5734,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { // Drop the simulated receiver and value. Return the value. Drop(2); Push(instr); - if (store->HasObservableSideEffects()) AddSimulate(expr->AssignmentId()); + if (store->HasObservableSideEffects()) { + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); + } return ast_context()->ReturnValue(Pop()); } else { @@ -5796,7 +5752,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { false, // is_store &has_side_effects); Push(load); - if (has_side_effects) AddSimulate(prop->LoadId()); + if (has_side_effects) AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); CHECK_ALIVE(VisitForValue(expr->value())); @@ -5805,7 +5761,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { HInstruction* instr = BuildBinaryOperation(operation, left, right); PushAndAdd(instr); - if (instr->HasObservableSideEffects()) AddSimulate(operation->id()); + if (instr->HasObservableSideEffects()) { + AddSimulate(operation->id(), REMOVABLE_SIMULATE); + } expr->RecordTypeFeedback(oracle(), zone()); HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(), @@ -5817,7 +5775,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { Drop(3); Push(instr); ASSERT(has_side_effects); // Stores always have side effects. - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); return ast_context()->ReturnValue(Pop()); } @@ -5940,7 +5898,7 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { context, var->index(), mode, Top()); AddInstruction(instr); if (instr->HasObservableSideEffects()) { - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); } return ast_context()->ReturnValue(Pop()); } @@ -5977,13 +5935,7 @@ void HGraphBuilder::VisitThrow(Throw* expr) { HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, Handle<Map> map, - LookupResult* lookup, - bool smi_and_map_check) { - if (smi_and_map_check) { - AddInstruction(new(zone()) HCheckNonSmi(object)); - AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone())); - } - + LookupResult* lookup) { int index = lookup->GetLocalFieldIndexFromMap(*map); if (index < 0) { // Negative property indices are in-object properties, indexed @@ -6014,7 +5966,7 @@ HInstruction* HGraphBuilder::BuildCallGetter(HValue* object, Handle<Map> map, Handle<JSFunction> getter, Handle<JSObject> holder) { - AddCheckConstantFunction(holder, object, map, true); + AddCheckConstantFunction(holder, object, map); AddInstruction(new(zone()) HPushArgument(object)); return new(zone()) HCallConstantFunction(getter, 1); } @@ -6029,17 +5981,29 @@ HInstruction* HGraphBuilder::BuildLoadNamedMonomorphic(HValue* object, LookupResult lookup(isolate()); map->LookupDescriptor(NULL, *name, &lookup); if (lookup.IsField()) { - return BuildLoadNamedField(object, map, &lookup, true); + AddCheckMapsWithTransitions(object, map); + return BuildLoadNamedField(object, map, &lookup); } // Handle a load of a constant known function. if (lookup.IsConstantFunction()) { - AddInstruction(new(zone()) HCheckNonSmi(object)); - AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone())); + AddCheckMapsWithTransitions(object, map); Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); return new(zone()) HConstant(function, Representation::Tagged()); } + // Handle a load from a known field somewhere in the protoype chain. + LookupInPrototypes(map, name, &lookup); + if (lookup.IsField()) { + Handle<JSObject> prototype(JSObject::cast(map->prototype())); + Handle<JSObject> holder(lookup.holder()); + Handle<Map> holder_map(holder->map()); + AddCheckMapsWithTransitions(object, map); + HInstruction* holder_value = + AddInstruction(new(zone()) HCheckPrototypeMaps(prototype, holder)); + return BuildLoadNamedField(holder_value, holder_map, &lookup); + } + // No luck, do a generic load. return BuildLoadNamedGeneric(object, name, expr); } @@ -6072,13 +6036,6 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case EXTERNAL_INT_ELEMENTS: case EXTERNAL_UNSIGNED_INT_ELEMENTS: { - if (!val->representation().IsInteger32()) { - val = AddInstruction(new(zone()) HChange( - val, - Representation::Integer32(), - true, // Truncate to int32. - false)); // Don't deoptimize undefined (irrelevant here). - } break; } case EXTERNAL_FLOAT_ELEMENTS: @@ -6095,13 +6052,15 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( UNREACHABLE(); break; } - return new(zone()) HStoreKeyedSpecializedArrayElement( - external_elements, checked_key, val, elements_kind); + return new(zone()) HStoreKeyed(external_elements, + checked_key, + val, + elements_kind); } else { ASSERT(val == NULL); - HLoadKeyedSpecializedArrayElement* load = - new(zone()) HLoadKeyedSpecializedArrayElement( - external_elements, checked_key, dependency, elements_kind); + HLoadKeyed* load = + new(zone()) HLoadKeyed( + external_elements, checked_key, dependency, elements_kind); if (FLAG_opt_safe_uint32_operations && elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { graph()->RecordUint32Instruction(load); @@ -6120,10 +6079,6 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, if (is_store) { ASSERT(val != NULL); switch (elements_kind) { - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - return new(zone()) HStoreKeyedFastDoubleElement( - elements, checked_key, val); case FAST_SMI_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: // Smi-only arrays need a smi check. @@ -6131,7 +6086,9 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, // Fall through. case FAST_ELEMENTS: case FAST_HOLEY_ELEMENTS: - return new(zone()) HStoreKeyedFastElement( + case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + return new(zone()) HStoreKeyed( elements, checked_key, val, elements_kind); default: UNREACHABLE(); @@ -6139,16 +6096,10 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, } } // It's an element load (!is_store). - HoleCheckMode mode = IsFastPackedElementsKind(elements_kind) ? - OMIT_HOLE_CHECK : - PERFORM_HOLE_CHECK; - if (IsFastDoubleElementsKind(elements_kind)) { - return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key, - load_dependency, mode); - } else { // Smi or Object elements. - return new(zone()) HLoadKeyedFastElement(elements, checked_key, - load_dependency, elements_kind); - } + return new(zone()) HLoadKeyed(elements, + checked_key, + load_dependency, + elements_kind); } @@ -6375,7 +6326,6 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, HInstruction* elements_kind_instr = AddInstruction(new(zone()) HElementsKind(object)); - HCompareConstantEqAndBranch* elements_kind_branch = NULL; HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object, checkspec)); HLoadExternalArrayPointer* external_elements = NULL; @@ -6406,8 +6356,9 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, if (type_todo[elements_kind]) { HBasicBlock* if_true = graph()->CreateBasicBlock(); HBasicBlock* if_false = graph()->CreateBasicBlock(); - elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( - elements_kind_instr, elements_kind, Token::EQ_STRICT); + HCompareConstantEqAndBranch* elements_kind_branch = + new(zone()) HCompareConstantEqAndBranch( + elements_kind_instr, elements_kind, Token::EQ_STRICT); elements_kind_branch->SetSuccessorAt(0, if_true); elements_kind_branch->SetSuccessorAt(1, if_false); current_block()->Finish(elements_kind_branch); @@ -6549,6 +6500,7 @@ void HGraphBuilder::EnsureArgumentsArePushedForAccess() { // Push arguments when entering inlined function. HEnterInlined* entry = function_state()->entry(); + entry->set_arguments_pushed(); ZoneList<HValue*>* arguments_values = entry->arguments_values(); @@ -6678,7 +6630,7 @@ void HGraphBuilder::VisitProperty(Property* expr) { Handle<JSFunction> getter; Handle<JSObject> holder; if (LookupGetter(map, name, &getter, &holder)) { - AddCheckConstantFunction(holder, Top(), map, true); + AddCheckConstantFunction(holder, Top(), map); if (FLAG_inline_accessors && TryInlineGetter(getter, expr)) return; AddInstruction(new(zone()) HPushArgument(Pop())); instr = new(zone()) HCallConstantFunction(getter, 1); @@ -6704,10 +6656,10 @@ void HGraphBuilder::VisitProperty(Property* expr) { &has_side_effects); if (has_side_effects) { if (ast_context()->IsEffect()) { - AddSimulate(expr->id()); + AddSimulate(expr->id(), REMOVABLE_SIMULATE); } else { Push(load); - AddSimulate(expr->id()); + AddSimulate(expr->id(), REMOVABLE_SIMULATE); Drop(1); } } @@ -6718,22 +6670,23 @@ void HGraphBuilder::VisitProperty(Property* expr) { } +void HGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, + Handle<Map> receiver_map) { + if (!holder.is_null()) { + AddInstruction(new(zone()) HCheckPrototypeMaps( + Handle<JSObject>(JSObject::cast(receiver_map->prototype())), holder)); + } +} + + void HGraphBuilder::AddCheckConstantFunction(Handle<JSObject> holder, HValue* receiver, - Handle<Map> receiver_map, - bool smi_and_map_check) { + Handle<Map> receiver_map) { // Constant functions have the nice property that the map will change if they // are overwritten. Therefore it is enough to check the map of the holder and // its prototypes. - if (smi_and_map_check) { - AddInstruction(new(zone()) HCheckNonSmi(receiver)); - AddInstruction(HCheckMaps::NewWithTransitions(receiver, receiver_map, - zone())); - } - if (!holder.is_null()) { - AddInstruction(new(zone()) HCheckPrototypeMaps( - Handle<JSObject>(JSObject::cast(receiver_map->prototype())), holder)); - } + AddCheckMapsWithTransitions(receiver, receiver_map); + AddCheckPrototypeMaps(holder, receiver_map); } @@ -6815,7 +6768,7 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, set_current_block(if_true); expr->ComputeTarget(map, name); - AddCheckConstantFunction(expr->holder(), receiver, map, false); + AddCheckPrototypeMaps(expr->holder(), map); if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { Handle<JSFunction> caller = info()->closure(); SmartArrayPointer<char> caller_name = @@ -7161,9 +7114,8 @@ bool HGraphBuilder::TryInline(CallKind call_kind, inlined_count_ += nodes_added; ASSERT(unoptimized_code->kind() == Code::FUNCTION); - Handle<Object> maybe_type_info(unoptimized_code->type_feedback_info()); Handle<TypeFeedbackInfo> type_info( - Handle<TypeFeedbackInfo>::cast(maybe_type_info)); + TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); graph()->update_type_change_checksum(type_info->own_type_change_checksum()); TraceInline(target, caller, NULL); @@ -7301,6 +7253,9 @@ bool HGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra) { if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); switch (id) { + case kMathExp: + if (!FLAG_fast_math) break; + // Fall through if FLAG_fast_math. case kMathRound: case kMathAbs: case kMathSqrt: @@ -7361,6 +7316,9 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, return true; } break; + case kMathExp: + if (!FLAG_fast_math) break; + // Fall through if FLAG_fast_math. case kMathRound: case kMathFloor: case kMathAbs: @@ -7370,7 +7328,7 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, case kMathCos: case kMathTan: if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true); + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); HValue* argument = Pop(); HValue* context = environment()->LookupContext(); Drop(1); // Receiver. @@ -7383,7 +7341,7 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, break; case kMathPow: if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true); + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); HValue* right = Pop(); HValue* left = Pop(); Pop(); // Pop receiver. @@ -7425,7 +7383,7 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, break; case kMathRandom: if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true); + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); Drop(1); // Receiver. HValue* context = environment()->LookupContext(); HGlobalObject* global_object = new(zone()) HGlobalObject(context); @@ -7438,7 +7396,7 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, case kMathMax: case kMathMin: if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true); + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); HValue* right = Pop(); HValue* left = Pop(); Drop(1); // Receiver. @@ -7487,7 +7445,7 @@ bool HGraphBuilder::TryCallApply(Call* expr) { VisitForValue(prop->obj()); if (HasStackOverflow() || current_block() == NULL) return true; HValue* function = Top(); - AddCheckConstantFunction(expr->holder(), function, function_map, true); + AddCheckConstantFunction(expr->holder(), function, function_map); Drop(1); VisitForValue(args->at(0)); @@ -7537,6 +7495,55 @@ bool HGraphBuilder::TryCallApply(Call* expr) { } +// Checks if all maps in |types| are from the same family, i.e., are elements +// transitions of each other. Returns either NULL if they are not from the same +// family, or a Map* indicating the map with the first elements kind of the +// family that is in the list. +static Map* CheckSameElementsFamily(SmallMapList* types) { + if (types->length() <= 1) return NULL; + // Check if all maps belong to the same transition family. + Map* kinds[kFastElementsKindCount]; + Map* first_map = *types->first(); + ElementsKind first_kind = first_map->elements_kind(); + if (!IsFastElementsKind(first_kind)) return NULL; + int first_index = GetSequenceIndexFromFastElementsKind(first_kind); + int last_index = first_index; + + for (int i = 0; i < kFastElementsKindCount; i++) kinds[i] = NULL; + + kinds[first_index] = first_map; + + for (int i = 1; i < types->length(); ++i) { + Map* map = *types->at(i); + ElementsKind elements_kind = map->elements_kind(); + if (!IsFastElementsKind(elements_kind)) return NULL; + int index = GetSequenceIndexFromFastElementsKind(elements_kind); + if (index < first_index) { + first_index = index; + } else if (index > last_index) { + last_index = index; + } else if (kinds[index] != map) { + return NULL; + } + kinds[index] = map; + } + + Map* current = kinds[first_index]; + for (int i = first_index + 1; i <= last_index; i++) { + Map* next = kinds[i]; + if (next != NULL) { + ElementsKind current_kind = next->elements_kind(); + if (next != current->LookupElementsTransitionMap(current_kind)) { + return NULL; + } + current = next; + } + } + + return kinds[first_index]; +} + + void HGraphBuilder::VisitCall(Call* expr) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); @@ -7576,15 +7583,25 @@ void HGraphBuilder::VisitCall(Call* expr) { CHECK_ALIVE(VisitExpressions(expr->arguments())); Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); - SmallMapList* types = expr->GetReceiverTypes(); - HValue* receiver = - environment()->ExpressionStackAt(expr->arguments()->length()); - if (expr->IsMonomorphic()) { - Handle<Map> receiver_map = (types == NULL || types->is_empty()) + bool monomorphic = expr->IsMonomorphic(); + Handle<Map> receiver_map; + if (monomorphic) { + receiver_map = (types == NULL || types->is_empty()) ? Handle<Map>::null() : types->first(); + } else { + Map* family_map = CheckSameElementsFamily(types); + if (family_map != NULL) { + receiver_map = Handle<Map>(family_map); + monomorphic = expr->ComputeTarget(receiver_map, name); + } + } + + HValue* receiver = + environment()->ExpressionStackAt(expr->arguments()->length()); + if (monomorphic) { if (TryInlineBuiltinMethodCall(expr, receiver, receiver_map, @@ -7606,7 +7623,7 @@ void HGraphBuilder::VisitCall(Call* expr) { call = PreProcessCall( new(zone()) HCallNamed(context, name, argument_count)); } else { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true); + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); if (TryInlineCall(expr)) return; call = PreProcessCall( @@ -7629,7 +7646,7 @@ void HGraphBuilder::VisitCall(Call* expr) { VariableProxy* proxy = expr->expression()->AsVariableProxy(); bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); - if (proxy != NULL && proxy->var()->is_possibly_eval()) { + if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { return Bailout("possible direct call to eval"); } @@ -7955,14 +7972,13 @@ void HGraphBuilder::VisitSub(UnaryOperation* expr) { HInstruction* instr = new(zone()) HMul(context, value, graph_->GetConstantMinus1()); TypeInfo info = oracle()->UnaryType(expr); + Representation rep = ToRepresentation(info); if (info.IsUninitialized()) { AddInstruction(new(zone()) HSoftDeoptimize); current_block()->MarkAsDeoptimizing(); info = TypeInfo::Unknown(); } - Representation rep = ToRepresentation(info); - TraceRepresentation(expr->op(), info, instr, rep); - instr->AssumeRepresentation(rep); + HBinaryOperation::cast(instr)->set_observed_input_representation(rep, rep); return ast_context()->ReturnInstruction(instr, expr->id()); } @@ -8051,8 +8067,11 @@ HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input, : graph_->GetConstantMinus1(); HValue* context = environment()->LookupContext(); HInstruction* instr = new(zone()) HAdd(context, Top(), delta); - TraceRepresentation(expr->op(), info, instr, rep); + // We can't insert a simulate here, because it would break deoptimization, + // so the HAdd must not have side effects, so we must freeze its + // representation. instr->AssumeRepresentation(rep); + instr->ClearAllSideEffects(); AddInstruction(instr); return instr; } @@ -8126,7 +8145,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { new(zone()) HStoreContextSlot(context, var->index(), mode, after); AddInstruction(instr); if (instr->HasObservableSideEffects()) { - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); } break; } @@ -8167,7 +8186,9 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { load = BuildLoadNamedGeneric(object, name, prop); } PushAndAdd(load); - if (load->HasObservableSideEffects()) AddSimulate(prop->LoadId()); + if (load->HasObservableSideEffects()) { + AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); + } after = BuildIncrement(returns_original_input, expr); input = Pop(); @@ -8195,7 +8216,9 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { // necessary. environment()->SetExpressionStackAt(0, after); if (returns_original_input) environment()->SetExpressionStackAt(1, input); - if (store->HasObservableSideEffects()) AddSimulate(expr->AssignmentId()); + if (store->HasObservableSideEffects()) { + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); + } } else { // Keyed property. @@ -8212,7 +8235,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { false, // is_store &has_side_effects); Push(load); - if (has_side_effects) AddSimulate(prop->LoadId()); + if (has_side_effects) AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); after = BuildIncrement(returns_original_input, expr); input = Pop(); @@ -8230,7 +8253,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { environment()->SetExpressionStackAt(0, after); if (returns_original_input) environment()->SetExpressionStackAt(1, input); ASSERT(has_side_effects); // Stores always have side effects. - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); } } @@ -8251,21 +8274,82 @@ HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* context, return new(zone()) HStringCharCodeAt(context, string, checked_index); } +// Checks if the given shift amounts have form: (sa) and (32 - sa). +static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, + HValue* const32_minus_sa) { + if (!const32_minus_sa->IsSub()) return false; + HSub* sub = HSub::cast(const32_minus_sa); + HValue* const32 = sub->left(); + if (!const32->IsConstant() || + HConstant::cast(const32)->Integer32Value() != 32) { + return false; + } + return (sub->right() == sa); +} + + +// Checks if the left and the right are shift instructions with the oposite +// directions that can be replaced by one rotate right instruction or not. +// Returns the operand and the shift amount for the rotate instruction in the +// former case. +bool HGraphBuilder::MatchRotateRight(HValue* left, + HValue* right, + HValue** operand, + HValue** shift_amount) { + HShl* shl; + HShr* shr; + if (left->IsShl() && right->IsShr()) { + shl = HShl::cast(left); + shr = HShr::cast(right); + } else if (left->IsShr() && right->IsShl()) { + shl = HShl::cast(right); + shr = HShr::cast(left); + } else { + return false; + } + + if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) && + !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) { + return false; + } + *operand= shr->left(); + *shift_amount = shr->right(); + return true; +} + + +bool CanBeZero(HValue *right) { + if (right->IsConstant()) { + HConstant* right_const = HConstant::cast(right); + if (right_const->HasInteger32Value() && + (right_const->Integer32Value() & 0x1f) != 0) { + return false; + } + } + return true; +} + HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, HValue* left, HValue* right) { HValue* context = environment()->LookupContext(); - TypeInfo info = oracle()->BinaryType(expr); - if (info.IsUninitialized()) { + TypeInfo left_info, right_info, result_info, combined_info; + oracle()->BinaryType(expr, &left_info, &right_info, &result_info); + Representation left_rep = ToRepresentation(left_info); + Representation right_rep = ToRepresentation(right_info); + Representation result_rep = ToRepresentation(result_info); + if (left_info.IsUninitialized()) { + // Can't have initialized one but not the other. + ASSERT(right_info.IsUninitialized()); AddInstruction(new(zone()) HSoftDeoptimize); current_block()->MarkAsDeoptimizing(); - info = TypeInfo::Unknown(); + left_info = right_info = TypeInfo::Unknown(); } HInstruction* instr = NULL; switch (expr->op()) { case Token::ADD: - if (info.IsString()) { + if (left_info.IsString() && right_info.IsString()) { AddInstruction(new(zone()) HCheckNonSmi(left)); AddInstruction(HCheckInstanceType::NewIsString(left, zone())); AddInstruction(new(zone()) HCheckNonSmi(right)); @@ -8289,25 +8373,26 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, break; case Token::BIT_XOR: case Token::BIT_AND: - case Token::BIT_OR: instr = HBitwise::NewHBitwise(zone(), expr->op(), context, left, right); break; + case Token::BIT_OR: { + HValue* operand, *shift_amount; + if (left_info.IsInteger32() && right_info.IsInteger32() && + MatchRotateRight(left, right, &operand, &shift_amount)) { + instr = new(zone()) HRor(context, operand, shift_amount); + } else { + instr = HBitwise::NewHBitwise(zone(), expr->op(), context, left, right); + } + break; + } case Token::SAR: instr = HSar::NewHSar(zone(), context, left, right); break; case Token::SHR: instr = HShr::NewHShr(zone(), context, left, right); - if (FLAG_opt_safe_uint32_operations && instr->IsShr()) { - bool can_be_shift_by_zero = true; - if (right->IsConstant()) { - HConstant* right_const = HConstant::cast(right); - if (right_const->HasInteger32Value() && - (right_const->Integer32Value() & 0x1f) != 0) { - can_be_shift_by_zero = false; - } - } - - if (can_be_shift_by_zero) graph()->RecordUint32Instruction(instr); + if (FLAG_opt_safe_uint32_operations && instr->IsShr() && + CanBeZero(right)) { + graph()->RecordUint32Instruction(instr); } break; case Token::SHL: @@ -8317,23 +8402,11 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, UNREACHABLE(); } - // If we hit an uninitialized binary op stub we will get type info - // for a smi operation. If one of the operands is a constant string - // do not generate code assuming it is a smi operation. - if (info.IsSmi() && - ((left->IsConstant() && HConstant::cast(left)->handle()->IsString()) || - (right->IsConstant() && HConstant::cast(right)->handle()->IsString()))) { - return instr; - } - Representation rep = ToRepresentation(info); - // We only generate either int32 or generic tagged bitwise operations. - if (instr->IsBitwiseBinaryOperation()) { - HBitwiseBinaryOperation::cast(instr)-> - InitializeObservedInputRepresentation(rep); - if (rep.IsDouble()) rep = Representation::Integer32(); + if (instr->IsBinaryOperation()) { + HBinaryOperation* binop = HBinaryOperation::cast(instr); + binop->set_observed_input_representation(left_rep, right_rep); + binop->initialize_output_representation(result_rep); } - TraceRepresentation(expr->op(), info, instr, rep); - instr->AssumeRepresentation(rep); return instr; } @@ -8477,27 +8550,8 @@ void HGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { } -void HGraphBuilder::TraceRepresentation(Token::Value op, - TypeInfo info, - HValue* value, - Representation rep) { - if (!FLAG_trace_representation) return; - // TODO(svenpanne) Under which circumstances are we actually not flexible? - // At first glance, this looks a bit weird... - bool flexible = value->CheckFlag(HValue::kFlexibleRepresentation); - PrintF("Operation %s has type info %s, %schange representation assumption " - "for %s (ID %d) from %s to %s\n", - Token::Name(op), - info.ToString(), - flexible ? "" : " DO NOT ", - value->Mnemonic(), - graph_->GetMaximumValueID(), - value->representation().Mnemonic(), - rep.Mnemonic()); -} - - Representation HGraphBuilder::ToRepresentation(TypeInfo info) { + if (info.IsUninitialized()) return Representation::None(); if (info.IsSmi()) return Representation::Integer32(); if (info.IsInteger32()) return Representation::Integer32(); if (info.IsDouble()) return Representation::Double(); @@ -8595,13 +8649,17 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { return ast_context()->ReturnControl(instr, expr->id()); } - TypeInfo type_info = oracle()->CompareType(expr); + TypeInfo left_type, right_type, overall_type_info; + oracle()->CompareType(expr, &left_type, &right_type, &overall_type_info); + Representation combined_rep = ToRepresentation(overall_type_info); + Representation left_rep = ToRepresentation(left_type); + Representation right_rep = ToRepresentation(right_type); // Check if this expression was ever executed according to type feedback. // Note that for the special typeof/null/undefined cases we get unknown here. - if (type_info.IsUninitialized()) { + if (overall_type_info.IsUninitialized()) { AddInstruction(new(zone()) HSoftDeoptimize); current_block()->MarkAsDeoptimizing(); - type_info = TypeInfo::Unknown(); + overall_type_info = left_type = right_type = TypeInfo::Unknown(); } CHECK_ALIVE(VisitForValue(expr->left())); @@ -8673,17 +8731,15 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { HIn* result = new(zone()) HIn(context, left, right); result->set_position(expr->position()); return ast_context()->ReturnInstruction(result, expr->id()); - } else if (type_info.IsNonPrimitive()) { + } else if (overall_type_info.IsNonPrimitive()) { switch (op) { case Token::EQ: case Token::EQ_STRICT: { // Can we get away with map check and not instance type check? Handle<Map> map = oracle()->GetCompareMap(expr); if (!map.is_null()) { - AddInstruction(new(zone()) HCheckNonSmi(left)); - AddInstruction(HCheckMaps::NewWithTransitions(left, map, zone())); - AddInstruction(new(zone()) HCheckNonSmi(right)); - AddInstruction(HCheckMaps::NewWithTransitions(right, map, zone())); + AddCheckMapsWithTransitions(left, map); + AddCheckMapsWithTransitions(right, map); HCompareObjectEqAndBranch* result = new(zone()) HCompareObjectEqAndBranch(left, right); result->set_position(expr->position()); @@ -8702,8 +8758,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { default: return Bailout("Unsupported non-primitive compare"); } - } else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) && - (op == Token::EQ || op == Token::EQ_STRICT)) { + } else if (overall_type_info.IsSymbol() && Token::IsEqualityOp(op)) { AddInstruction(new(zone()) HCheckNonSmi(left)); AddInstruction(HCheckInstanceType::NewIsSymbol(left, zone())); AddInstruction(new(zone()) HCheckNonSmi(right)); @@ -8713,17 +8768,17 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { result->set_position(expr->position()); return ast_context()->ReturnControl(result, expr->id()); } else { - Representation r = ToRepresentation(type_info); - if (r.IsTagged()) { + if (combined_rep.IsTagged() || combined_rep.IsNone()) { HCompareGeneric* result = new(zone()) HCompareGeneric(context, left, right, op); + result->set_observed_input_representation(left_rep, right_rep); result->set_position(expr->position()); return ast_context()->ReturnInstruction(result, expr->id()); } else { HCompareIDAndBranch* result = new(zone()) HCompareIDAndBranch(left, right, op); + result->set_observed_input_representation(left_rep, right_rep); result->set_position(expr->position()); - result->SetInputRepresentation(r); return ast_context()->ReturnControl(result, expr->id()); } } @@ -8810,7 +8865,9 @@ void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* declaration) { HStoreContextSlot* store = new(zone()) HStoreContextSlot( context, variable->index(), HStoreContextSlot::kNoCheck, value); AddInstruction(store); - if (store->HasObservableSideEffects()) AddSimulate(proxy->id()); + if (store->HasObservableSideEffects()) { + AddSimulate(proxy->id(), REMOVABLE_SIMULATE); + } } break; case Variable::LOOKUP: @@ -8846,7 +8903,9 @@ void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* declaration) { HStoreContextSlot* store = new(zone()) HStoreContextSlot( context, variable->index(), HStoreContextSlot::kNoCheck, value); AddInstruction(store); - if (store->HasObservableSideEffects()) AddSimulate(proxy->id()); + if (store->HasObservableSideEffects()) { + AddSimulate(proxy->id(), REMOVABLE_SIMULATE); + } break; } case Variable::LOOKUP: @@ -8890,6 +8949,11 @@ void HGraphBuilder::VisitModuleUrl(ModuleUrl* module) { } +void HGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) { + UNREACHABLE(); +} + + // Generators for inline runtime functions. // Support for types. void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { @@ -9025,8 +9089,10 @@ void HGraphBuilder::GenerateArguments(CallRuntime* call) { HInstruction* elements = AddInstruction( new(zone()) HArgumentsElements(false)); HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); + HInstruction* checked_index = + AddInstruction(new(zone()) HBoundsCheck(index, length)); HAccessArgumentsAt* result = - new(zone()) HAccessArgumentsAt(elements, length, index); + new(zone()) HAccessArgumentsAt(elements, length, checked_index); return ast_context()->ReturnInstruction(result, call->id()); } @@ -9059,6 +9125,39 @@ void HGraphBuilder::GenerateDateField(CallRuntime* call) { } +void HGraphBuilder::GenerateOneByteSeqStringSetChar( + CallRuntime* call) { + ASSERT(call->arguments()->length() == 3); + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); + CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); + CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); + HValue* value = Pop(); + HValue* index = Pop(); + HValue* string = Pop(); + HSeqStringSetChar* result = new(zone()) HSeqStringSetChar( + String::ONE_BYTE_ENCODING, string, index, value); + return ast_context()->ReturnInstruction(result, call->id()); +} + + +void HGraphBuilder::GenerateTwoByteSeqStringSetChar( + CallRuntime* call) { + ASSERT(call->arguments()->length() == 3); + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); + CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); + CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); + HValue* value = Pop(); + HValue* index = Pop(); + HValue* string = Pop(); + HValue* context = environment()->LookupContext(); + HStringCharCodeAt* char_code = BuildStringCharCodeAt(context, string, index); + AddInstruction(char_code); + HSeqStringSetChar* result = new(zone()) HSeqStringSetChar( + String::TWO_BYTE_ENCODING, string, index, value); + return ast_context()->ReturnInstruction(result, call->id()); +} + + void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) { ASSERT(call->arguments()->length() == 2); CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); @@ -9391,6 +9490,7 @@ HEnvironment::HEnvironment(HEnvironment* outer, specials_count_(1), local_count_(0), outer_(outer), + entry_(NULL), pop_count_(0), push_count_(0), ast_id_(BailoutId::None()), @@ -9407,6 +9507,7 @@ HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone) specials_count_(1), local_count_(0), outer_(NULL), + entry_(NULL), pop_count_(0), push_count_(0), ast_id_(other->ast_id()), @@ -9427,6 +9528,7 @@ HEnvironment::HEnvironment(HEnvironment* outer, parameter_count_(arguments), local_count_(0), outer_(outer), + entry_(NULL), pop_count_(0), push_count_(0), ast_id_(BailoutId::None()), @@ -9455,6 +9557,7 @@ void HEnvironment::Initialize(const HEnvironment* other) { parameter_count_ = other->parameter_count_; local_count_ = other->local_count_; if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. + entry_ = other->entry_; pop_count_ = other->pop_count_; push_count_ = other->push_count_; ast_id_ = other->ast_id_; @@ -9900,28 +10003,43 @@ void HStatistics::Print() { double size_percent = static_cast<double>(size) * 100 / total_size_; PrintF(" %8u bytes / %4.1f %%\n", size, size_percent); } + + PrintF("---------------------------------------------------------------\n"); + int64_t total = create_graph_ + optimize_graph_ + generate_code_; + PrintF("%30s - %7.3f ms / %4.1f %% \n", + "Create graph", + static_cast<double>(create_graph_) / 1000, + static_cast<double>(create_graph_) * 100 / total); + PrintF("%30s - %7.3f ms / %4.1f %% \n", + "Optimize graph", + static_cast<double>(optimize_graph_) / 1000, + static_cast<double>(optimize_graph_) * 100 / total); + PrintF("%30s - %7.3f ms / %4.1f %% \n", + "Generate and install code", + static_cast<double>(generate_code_) / 1000, + static_cast<double>(generate_code_) * 100 / total); + PrintF("---------------------------------------------------------------\n"); + PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n", + "Total", + static_cast<double>(total) / 1000, + static_cast<double>(total) / full_code_gen_); + double source_size_in_kb = static_cast<double>(source_size_) / 1024; double normalized_time = source_size_in_kb > 0 - ? (static_cast<double>(sum) / 1000) / source_size_in_kb + ? (static_cast<double>(total) / 1000) / source_size_in_kb : 0; - double normalized_bytes = source_size_in_kb > 0 - ? total_size_ / source_size_in_kb + double normalized_size_in_kb = source_size_in_kb > 0 + ? total_size_ / 1024 / source_size_in_kb : 0; - PrintF("%30s - %7.3f ms %7.3f bytes\n", "Sum", - normalized_time, normalized_bytes); - PrintF("---------------------------------------------------------------\n"); - PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n", - "Total", - static_cast<double>(total_) / 1000, - static_cast<double>(total_) / full_code_gen_); + PrintF("%30s - %7.3f ms %7.3f kB allocated\n", + "Average per kB source", + normalized_time, normalized_size_in_kb); } void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) { if (name == HPhase::kFullCodeGen) { full_code_gen_ += ticks; - } else if (name == HPhase::kTotal) { - total_ += ticks; } else { total_size_ += size; for (int i = 0; i < names_.length(); ++i) { @@ -9939,8 +10057,6 @@ void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) { const char* const HPhase::kFullCodeGen = "Full code generator"; -const char* const HPhase::kTotal = "Total"; - void HPhase::Begin(const char* name, HGraph* graph, |