diff options
Diffstat (limited to 'deps/v8/src/hydrogen.cc')
-rw-r--r-- | deps/v8/src/hydrogen.cc | 1403 |
1 files changed, 627 insertions, 776 deletions
diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index f9ee50c1b..15ef5ed0b 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -649,7 +649,7 @@ HConstant* HGraph::GetConstant##Name() { \ if (!constant_##name##_.is_set()) { \ HConstant* constant = new(zone()) HConstant( \ isolate()->factory()->name##_value(), \ - UniqueValueId(isolate()->heap()->name##_value()), \ + UniqueValueId::name##_value(isolate()->heap()), \ Representation::Tagged(), \ htype, \ false, \ @@ -828,7 +828,6 @@ void HGraphBuilder::IfBuilder::Else() { ASSERT(!captured_); ASSERT(!finished_); last_true_block_ = builder_->current_block(); - ASSERT(first_true_block_ == NULL || !last_true_block_->IsFinished()); builder_->set_current_block(first_false_block_); did_else_ = true; } @@ -864,9 +863,11 @@ void HGraphBuilder::IfBuilder::End() { if (!did_else_) { last_true_block_ = builder_->current_block(); } - if (first_true_block_ == NULL) { + if (last_true_block_ == NULL || last_true_block_->IsFinished()) { + ASSERT(did_else_); // Return on true. Nothing to do, just continue the false block. - } else if (first_false_block_ == NULL) { + } else if (first_false_block_ == NULL || + (did_else_ && builder_->current_block()->IsFinished())) { // Deopt on false. Nothing to do except switching to the true block. builder_->set_current_block(last_true_block_); } else { @@ -906,6 +907,24 @@ HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, header_block_ = builder->CreateLoopHeaderBlock(); body_block_ = NULL; exit_block_ = NULL; + exit_trampoline_block_ = NULL; + increment_amount_ = builder_->graph()->GetConstant1(); +} + + +HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, + HValue* context, + LoopBuilder::Direction direction, + HValue* increment_amount) + : builder_(builder), + context_(context), + direction_(direction), + finished_(false) { + header_block_ = builder->CreateLoopHeaderBlock(); + body_block_ = NULL; + exit_block_ = NULL; + exit_trampoline_block_ = NULL; + increment_amount_ = increment_amount; } @@ -921,12 +940,14 @@ HValue* HGraphBuilder::LoopBuilder::BeginBody( HEnvironment* body_env = env->Copy(); HEnvironment* exit_env = env->Copy(); - body_block_ = builder_->CreateBasicBlock(body_env); - exit_block_ = builder_->CreateBasicBlock(exit_env); // Remove the phi from the expression stack body_env->Pop(); + exit_env->Pop(); + body_block_ = builder_->CreateBasicBlock(body_env); + exit_block_ = builder_->CreateBasicBlock(exit_env); builder_->set_current_block(header_block_); + env->Pop(); HCompareNumericAndBranch* compare = new(zone()) HCompareNumericAndBranch(phi_, terminating, token); compare->SetSuccessorAt(0, body_block_); @@ -950,15 +971,26 @@ HValue* HGraphBuilder::LoopBuilder::BeginBody( } +void HGraphBuilder::LoopBuilder::Break() { + if (exit_trampoline_block_ == NULL) { + // Its the first time we saw a break. + HEnvironment* env = exit_block_->last_environment()->Copy(); + exit_trampoline_block_ = builder_->CreateBasicBlock(env); + exit_block_->GotoNoSimulate(exit_trampoline_block_); + } + + builder_->current_block()->GotoNoSimulate(exit_trampoline_block_); +} + + void HGraphBuilder::LoopBuilder::EndBody() { ASSERT(!finished_); if (direction_ == kPostIncrement || direction_ == kPostDecrement) { - HValue* one = builder_->graph()->GetConstant1(); if (direction_ == kPostIncrement) { - increment_ = HAdd::New(zone(), context_, phi_, one); + increment_ = HAdd::New(zone(), context_, phi_, increment_amount_); } else { - increment_ = HSub::New(zone(), context_, phi_, one); + increment_ = HSub::New(zone(), context_, phi_, increment_amount_); } increment_->ClearFlag(HValue::kCanOverflow); builder_->AddInstruction(increment_); @@ -970,9 +1002,11 @@ void HGraphBuilder::LoopBuilder::EndBody() { last_block->GotoNoSimulate(header_block_); header_block_->loop_information()->RegisterBackEdge(last_block); - builder_->set_current_block(exit_block_); - // Pop the phi from the expression stack - builder_->environment()->Pop(); + if (exit_trampoline_block_ != NULL) { + builder_->set_current_block(exit_trampoline_block_); + } else { + builder_->set_current_block(exit_block_); + } finished_ = true; } @@ -1191,7 +1225,7 @@ void HGraphBuilder::BuildTransitionElementsKind(HValue* object, } if (!IsSimpleMapChangeTransition(from_kind, to_kind)) { - HInstruction* elements = AddLoadElements(object, NULL); + HInstruction* elements = AddLoadElements(object); HInstruction* empty_fixed_array = Add<HConstant>( isolate()->factory()->empty_fixed_array()); @@ -1219,10 +1253,9 @@ void HGraphBuilder::BuildTransitionElementsKind(HValue* object, HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( - HValue* object, + HValue* checked_object, HValue* key, HValue* val, - HCheckMaps* mapcheck, bool is_js_array, ElementsKind elements_kind, bool is_store, @@ -1237,13 +1270,12 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( // generated store code. if ((elements_kind == FAST_HOLEY_ELEMENTS) || (elements_kind == FAST_ELEMENTS && is_store)) { - if (mapcheck != NULL) { - mapcheck->ClearGVNFlag(kDependsOnElementsKind); - } + checked_object->ClearGVNFlag(kDependsOnElementsKind); } + bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); bool fast_elements = IsFastObjectElementsKind(elements_kind); - HValue* elements = AddLoadElements(object, mapcheck); + HValue* elements = AddLoadElements(checked_object); if (is_store && (fast_elements || fast_smi_only_elements) && store_mode != STORE_NO_TRANSITION_HANDLE_COW) { HCheckMaps* check_cow_map = Add<HCheckMaps>( @@ -1252,8 +1284,8 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( } HInstruction* length = NULL; if (is_js_array) { - length = Add<HLoadNamedField>(object, - HObjectAccess::ForArrayLength(elements_kind), mapcheck); + length = Add<HLoadNamedField>( + checked_object, HObjectAccess::ForArrayLength(elements_kind)); } else { length = AddLoadFixedArrayLength(elements); } @@ -1283,7 +1315,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( Add<HLoadExternalArrayPointer>(elements); return AddExternalArrayElementAccess( external_elements, checked_key, val, - mapcheck, elements_kind, is_store); + checked_object, elements_kind, is_store); } } ASSERT(fast_smi_only_elements || @@ -1300,8 +1332,9 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( if (IsGrowStoreMode(store_mode)) { NoObservableSideEffectsScope no_effects(this); - elements = BuildCheckForCapacityGrow(object, elements, elements_kind, - length, key, is_js_array); + elements = BuildCheckForCapacityGrow(checked_object, elements, + elements_kind, length, key, + is_js_array); checked_key = key; } else { checked_key = Add<HBoundsCheck>(key, length); @@ -1309,9 +1342,8 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( if (is_store && (fast_elements || fast_smi_only_elements)) { if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { NoObservableSideEffectsScope no_effects(this); - - elements = BuildCopyElementsOnWrite(object, elements, elements_kind, - length); + elements = BuildCopyElementsOnWrite(checked_object, elements, + elements_kind, length); } else { HCheckMaps* check_cow_map = Add<HCheckMaps>( elements, isolate()->factory()->fixed_array_map(), @@ -1320,7 +1352,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( } } } - return AddFastElementAccess(elements, checked_key, val, mapcheck, + return AddFastElementAccess(elements, checked_key, val, checked_object, elements_kind, is_store, load_mode, store_mode); } @@ -1493,11 +1525,8 @@ HInstruction* HGraphBuilder::AddFastElementAccess( } -HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object, - HValue* typecheck) { - return Add<HLoadNamedField>(object, - HObjectAccess::ForElementsPointer(), - typecheck); +HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object) { + return Add<HLoadNamedField>(object, HObjectAccess::ForElementsPointer()); } @@ -1508,14 +1537,15 @@ HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(HValue* object) { HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) { - HValue* half_old_capacity = Add<HShr>(old_capacity, graph_->GetConstant1()); + HValue* half_old_capacity = AddUncasted<HShr>(old_capacity, + graph_->GetConstant1()); - HValue* new_capacity = Add<HAdd>(half_old_capacity, old_capacity); + HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity); new_capacity->ClearFlag(HValue::kCanOverflow); HValue* min_growth = Add<HConstant>(16); - new_capacity = Add<HAdd>(new_capacity, min_growth); + new_capacity = AddUncasted<HAdd>(new_capacity, min_growth); new_capacity->ClearFlag(HValue::kCanOverflow); return new_capacity; @@ -1679,22 +1709,12 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate, if (mode == TRACK_ALLOCATION_SITE) { size += AllocationMemento::kSize; } - int elems_offset = size; - InstanceType instance_type = IsFastDoubleElementsKind(kind) ? - FIXED_DOUBLE_ARRAY_TYPE : FIXED_ARRAY_TYPE; - if (length > 0) { - size += IsFastDoubleElementsKind(kind) - ? FixedDoubleArray::SizeFor(length) - : FixedArray::SizeFor(length); - } - // Allocate both the JS array and the elements array in one big - // allocation. This avoids multiple limit checks. HValue* size_in_bytes = Add<HConstant>(size); HInstruction* object = Add<HAllocate>(size_in_bytes, HType::JSObject(), NOT_TENURED, - instance_type); + JS_OBJECT_TYPE); // Copy the JS array part. for (int i = 0; i < JSArray::kSize; i += kPointerSize) { @@ -1711,10 +1731,17 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate, } if (length > 0) { - // Get hold of the elements array of the boilerplate and setup the - // elements pointer in the resulting object. - HValue* boilerplate_elements = AddLoadElements(boilerplate, NULL); - HValue* object_elements = Add<HInnerAllocatedObject>(object, elems_offset); + HValue* boilerplate_elements = AddLoadElements(boilerplate); + HValue* object_elements; + if (IsFastDoubleElementsKind(kind)) { + HValue* elems_size = Add<HConstant>(FixedDoubleArray::SizeFor(length)); + object_elements = Add<HAllocate>(elems_size, HType::JSArray(), + NOT_TENURED, FIXED_DOUBLE_ARRAY_TYPE); + } else { + HValue* elems_size = Add<HConstant>(FixedArray::SizeFor(length)); + object_elements = Add<HAllocate>(elems_size, HType::JSArray(), + NOT_TENURED, FIXED_ARRAY_TYPE); + } Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), object_elements); @@ -1747,22 +1774,35 @@ void HGraphBuilder::BuildCompareNil( int position, HIfContinuation* continuation) { IfBuilder if_nil(this, position); - bool needs_or = false; + bool some_case_handled = false; + bool some_case_missing = false; + if (type->Maybe(Type::Null())) { - if (needs_or) if_nil.Or(); + if (some_case_handled) if_nil.Or(); if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull()); - needs_or = true; + some_case_handled = true; + } else { + some_case_missing = true; } + if (type->Maybe(Type::Undefined())) { - if (needs_or) if_nil.Or(); + if (some_case_handled) if_nil.Or(); if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantUndefined()); - needs_or = true; + some_case_handled = true; + } else { + some_case_missing = true; } + if (type->Maybe(Type::Undetectable())) { - if (needs_or) if_nil.Or(); + if (some_case_handled) if_nil.Or(); if_nil.If<HIsUndetectableAndBranch>(value); + some_case_handled = true; } else { + some_case_missing = true; + } + + if (some_case_missing) { if_nil.Then(); if_nil.Else(); if (type->NumClasses() == 1) { @@ -1784,7 +1824,8 @@ void HGraphBuilder::BuildCompareNil( HValue* HGraphBuilder::BuildCreateAllocationMemento(HValue* previous_object, int previous_object_size, HValue* alloc_site) { - ASSERT(alloc_site != NULL); + // TODO(mvstanton): ASSERT altered to CHECK to diagnose chromium bug 284577 + CHECK(alloc_site != NULL); HInnerAllocatedObject* alloc_memento = Add<HInnerAllocatedObject>( previous_object, previous_object_size); Handle<Map> alloc_memento_map( @@ -1846,7 +1887,7 @@ HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { // map, because we can just load the map in that case. HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); return builder()->AddInstruction( - builder()->BuildLoadNamedField(constructor_function_, access, NULL)); + builder()->BuildLoadNamedField(constructor_function_, access)); } HInstruction* native_context = builder()->BuildGetNativeContext(); @@ -1867,7 +1908,7 @@ HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() { // Find the map near the constructor function HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); return builder()->AddInstruction( - builder()->BuildLoadNamedField(constructor_function_, access, NULL)); + builder()->BuildLoadNamedField(constructor_function_, access)); } @@ -2000,7 +2041,7 @@ HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) // constructor for the initial state relies on function_state_ == NULL // to know it's the initial state. function_state_= &initial_function_state_; - InitializeAstVisitor(); + InitializeAstVisitor(info->isolate()); } @@ -3963,13 +4004,20 @@ void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { } +static bool CanInlinePropertyAccess(Map* type) { + return type->IsJSObjectMap() && + !type->is_dictionary_map() && + !type->has_named_interceptor(); +} + + static void LookupInPrototypes(Handle<Map> map, Handle<String> name, LookupResult* lookup) { while (map->prototype()->IsJSObject()) { Handle<JSObject> holder(JSObject::cast(map->prototype())); - if (!holder->HasFastProperties()) break; map = Handle<Map>(holder->map()); + if (!CanInlinePropertyAccess(*map)) break; map->LookupDescriptor(*holder, *name, lookup); if (lookup->IsFound()) return; } @@ -4049,9 +4097,7 @@ static bool LookupSetter(Handle<Map> map, // size of all objects that are part of the graph. static bool IsFastLiteral(Handle<JSObject> boilerplate, int max_depth, - int* max_properties, - int* data_size, - int* pointer_size) { + int* max_properties) { if (boilerplate->map()->is_deprecated()) { Handle<Object> result = JSObject::TryMigrateInstance(boilerplate); if (result->IsSmi()) return false; @@ -4064,9 +4110,7 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate, Handle<FixedArrayBase> elements(boilerplate->elements()); if (elements->length() > 0 && elements->map() != isolate->heap()->fixed_cow_array_map()) { - if (boilerplate->HasFastDoubleElements()) { - *data_size += FixedDoubleArray::SizeFor(elements->length()); - } else if (boilerplate->HasFastObjectElements()) { + if (boilerplate->HasFastObjectElements()) { Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); int length = elements->length(); for (int i = 0; i < length; i++) { @@ -4076,15 +4120,12 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate, Handle<JSObject> value_object = Handle<JSObject>::cast(value); if (!IsFastLiteral(value_object, max_depth - 1, - max_properties, - data_size, - pointer_size)) { + max_properties)) { return false; } } } - *pointer_size += FixedArray::SizeFor(length); - } else { + } else if (!boilerplate->HasFastDoubleElements()) { return false; } } @@ -4099,7 +4140,6 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate, for (int i = 0; i < limit; i++) { PropertyDetails details = descriptors->GetDetails(i); if (details.type() != FIELD) continue; - Representation representation = details.representation(); int index = descriptors->GetFieldIndex(i); if ((*max_properties)-- == 0) return false; Handle<Object> value(boilerplate->InObjectPropertyAt(index), isolate); @@ -4107,18 +4147,12 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate, Handle<JSObject> value_object = Handle<JSObject>::cast(value); if (!IsFastLiteral(value_object, max_depth - 1, - max_properties, - data_size, - pointer_size)) { + max_properties)) { return false; } - } else if (representation.IsDouble()) { - *data_size += HeapNumber::kSize; } } } - - *pointer_size += boilerplate->map()->instance_size(); return true; } @@ -4128,32 +4162,21 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); Handle<JSFunction> closure = function_state()->compilation_info()->closure(); - HValue* context = environment()->context(); HInstruction* literal; // Check whether to use fast or slow deep-copying for boilerplate. - int data_size = 0; - int pointer_size = 0; int max_properties = kMaxFastLiteralProperties; - Handle<Object> original_boilerplate(closure->literals()->get( + Handle<Object> boilerplate(closure->literals()->get( expr->literal_index()), isolate()); - if (original_boilerplate->IsJSObject() && - IsFastLiteral(Handle<JSObject>::cast(original_boilerplate), + if (boilerplate->IsJSObject() && + IsFastLiteral(Handle<JSObject>::cast(boilerplate), kMaxFastLiteralDepth, - &max_properties, - &data_size, - &pointer_size)) { - Handle<JSObject> original_boilerplate_object = - Handle<JSObject>::cast(original_boilerplate); + &max_properties)) { Handle<JSObject> boilerplate_object = - DeepCopy(original_boilerplate_object); + Handle<JSObject>::cast(boilerplate); - literal = BuildFastLiteral(context, - boilerplate_object, - original_boilerplate_object, + literal = BuildFastLiteral(boilerplate_object, Handle<Object>::null(), - data_size, - pointer_size, DONT_TRACK_ALLOCATION_SITE); } else { NoObservableSideEffectsScope no_effects(this); @@ -4255,7 +4278,6 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { ASSERT(current_block()->HasPredecessor()); ZoneList<Expression*>* subexprs = expr->values(); int length = subexprs->length(); - HValue* context = environment()->context(); HInstruction* literal; Handle<AllocationSite> site; @@ -4289,10 +4311,10 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { ASSERT(!raw_boilerplate.is_null()); ASSERT(site->IsLiteralSite()); - Handle<JSObject> original_boilerplate_object = + Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(raw_boilerplate); ElementsKind boilerplate_elements_kind = - Handle<JSObject>::cast(original_boilerplate_object)->GetElementsKind(); + Handle<JSObject>::cast(boilerplate_object)->GetElementsKind(); // TODO(mvstanton): This heuristic is only a temporary solution. In the // end, we want to quit creating allocation site info after a certain number @@ -4301,26 +4323,12 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { boilerplate_elements_kind); // Check whether to use fast or slow deep-copying for boilerplate. - int data_size = 0; - int pointer_size = 0; int max_properties = kMaxFastLiteralProperties; - HCheckMaps* type_check = NULL; - if (IsFastLiteral(original_boilerplate_object, + if (IsFastLiteral(boilerplate_object, kMaxFastLiteralDepth, - &max_properties, - &data_size, - &pointer_size)) { - if (mode == TRACK_ALLOCATION_SITE) { - pointer_size += AllocationMemento::kSize; - } - - Handle<JSObject> boilerplate_object = DeepCopy(original_boilerplate_object); - literal = BuildFastLiteral(context, - boilerplate_object, - original_boilerplate_object, + &max_properties)) { + literal = BuildFastLiteral(boilerplate_object, site, - data_size, - pointer_size, mode); } else { NoObservableSideEffectsScope no_effects(this); @@ -4340,9 +4348,8 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { 3); // De-opt if elements kind changed from boilerplate_elements_kind. - Handle<Map> map = Handle<Map>(original_boilerplate_object->map(), - isolate()); - type_check = Add<HCheckMaps>(literal, map, top_info()); + Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate()); + literal = Add<HCheckMaps>(literal, map, top_info()); } // The array is expected in the bailout environment during computation @@ -4363,7 +4370,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { HValue* value = Pop(); if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral); - elements = AddLoadElements(literal, type_check); + elements = AddLoadElements(literal); HValue* key = Add<HConstant>(i); @@ -4398,8 +4405,8 @@ static bool ComputeLoadStoreField(Handle<Map> type, LookupResult* lookup, bool is_store) { ASSERT(!is_store || !type->is_observed()); - if (type->has_named_interceptor()) { - lookup->InterceptorResult(NULL); + if (!CanInlinePropertyAccess(*type)) { + lookup->NotFound(); return false; } // If we directly find a field, the access can be inlined. @@ -4425,7 +4432,7 @@ HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( - HValue* object, + HValue* checked_object, Handle<String> name, HValue* value, Handle<Map> map, @@ -4477,11 +4484,12 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( AddStoreMapConstant(heap_number, isolate()->factory()->heap_number_map()); Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(), value); - instr = New<HStoreNamedField>(object, heap_number_access, - heap_number); + instr = New<HStoreNamedField>(checked_object->ActualValue(), + heap_number_access, + heap_number); } else { // Already holds a HeapNumber; load the box and write its value field. - HInstruction* heap_number = Add<HLoadNamedField>(object, + HInstruction* heap_number = Add<HLoadNamedField>(checked_object, heap_number_access); heap_number->set_type(HType::HeapNumber()); instr = New<HStoreNamedField>(heap_number, @@ -4490,7 +4498,9 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( } } else { // This is a normal store. - instr = New<HStoreNamedField>(object, field_access, value); + instr = New<HStoreNamedField>(checked_object->ActualValue(), + field_access, + value); } if (transition_to_field) { @@ -4527,8 +4537,8 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( // Handle a store to a known field. LookupResult lookup(isolate()); if (ComputeLoadStoreField(map, name, &lookup, true)) { - AddCheckMap(object, map); - return BuildStoreNamedField(object, name, value, map, &lookup); + HCheckMaps* checked_object = AddCheckMap(object, map); + return BuildStoreNamedField(checked_object, name, value, map, &lookup); } // No luck, do a generic store. @@ -4539,8 +4549,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( static bool CanLoadPropertyFromPrototype(Handle<Map> map, Handle<Name> name, LookupResult* lookup) { - if (map->has_named_interceptor()) return false; - if (map->is_dictionary_map()) return false; + if (!CanInlinePropertyAccess(*map)) return false; map->LookupDescriptor(NULL, *name, lookup); if (lookup->IsFound()) return false; return true; @@ -4548,7 +4557,6 @@ static bool CanLoadPropertyFromPrototype(Handle<Map> map, HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( - Property* expr, HValue* object, SmallMapList* types, Handle<String> name) { @@ -4586,8 +4594,8 @@ HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( if (count == types->length()) { // Everything matched; can use monomorphic load. BuildCheckHeapObject(object); - HCheckMaps* type_check = Add<HCheckMaps>(object, types); - return BuildLoadNamedField(object, access, type_check); + HCheckMaps* checked_object = Add<HCheckMaps>(object, types); + return BuildLoadNamedField(checked_object, access); } if (count != 0) return NULL; @@ -4608,14 +4616,14 @@ HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( if (!lookup.IsField()) return NULL; BuildCheckHeapObject(object); - HCheckMaps* type_check = Add<HCheckMaps>(object, types); + Add<HCheckMaps>(object, types); Handle<JSObject> holder(lookup.holder()); Handle<Map> holder_map(holder->map()); - BuildCheckPrototypeMaps(Handle<JSObject>::cast(prototype), holder); - HValue* holder_value = Add<HConstant>(holder); - return BuildLoadNamedField(holder_value, - HObjectAccess::ForField(holder_map, &lookup, name), type_check); + HValue* checked_holder = BuildCheckPrototypeMaps( + Handle<JSObject>::cast(prototype), holder); + return BuildLoadNamedField(checked_holder, + HObjectAccess::ForField(holder_map, &lookup, name)); } @@ -4632,9 +4640,8 @@ static bool PrototypeChainCanNeverResolve( if (current->IsJSGlobalProxy() || current->IsGlobalObject() || !current->IsJSObject() || - JSObject::cast(current)->map()->has_named_interceptor() || - JSObject::cast(current)->IsAccessCheckNeeded() || - !JSObject::cast(current)->HasFastProperties()) { + !CanInlinePropertyAccess(JSObject::cast(current)->map()) || + JSObject::cast(current)->IsAccessCheckNeeded()) { return false; } @@ -4650,15 +4657,15 @@ static bool PrototypeChainCanNeverResolve( void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( - Property* expr, + int position, + BailoutId ast_id, HValue* object, SmallMapList* types, Handle<String> name) { - HInstruction* instr = TryLoadPolymorphicAsMonomorphic( - expr, object, types, name); + HInstruction* instr = TryLoadPolymorphicAsMonomorphic(object, types, name); if (instr != NULL) { - instr->set_position(expr->position()); - return ast_context()->ReturnInstruction(instr, expr->id()); + instr->set_position(position); + return ast_context()->ReturnInstruction(instr, ast_id); } // Something did not match; must use a polymorphic load. @@ -4669,8 +4676,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( LookupResult lookup(isolate()); if (ComputeLoadStoreField(map, name, &lookup, false) || (lookup.IsCacheable() && - !map->is_dictionary_map() && - !map->has_named_interceptor() && + CanInlinePropertyAccess(*map) && (lookup.IsConstant() || (!lookup.IsFound() && PrototypeChainCanNeverResolve(map, name))))) { @@ -4690,8 +4696,8 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( // TODO(verwaest): Merge logic with BuildLoadNamedMonomorphic. if (lookup.IsField()) { HObjectAccess access = HObjectAccess::ForField(map, &lookup, name); - HLoadNamedField* load = BuildLoadNamedField(object, access, compare); - load->set_position(expr->position()); + HLoadNamedField* load = BuildLoadNamedField(compare, access); + load->set_position(position); AddInstruction(load); if (!ast_context()->IsEffect()) Push(load); } else if (lookup.IsConstant()) { @@ -4722,22 +4728,23 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( if (count == types->length() && FLAG_deoptimize_uncommon_cases) { FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); } else { - HInstruction* load = BuildLoadNamedGeneric(object, name, expr); - load->set_position(expr->position()); + HValue* context = environment()->context(); + HInstruction* load = new(zone()) HLoadNamedGeneric(context, object, name); + load->set_position(position); AddInstruction(load); if (!ast_context()->IsEffect()) Push(load); if (join != NULL) { current_block()->Goto(join); } else { - Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); + Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); return; } } ASSERT(join != NULL); - join->SetJoinId(expr->id()); + join->SetJoinId(ast_id); set_current_block(join); if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); } @@ -4747,8 +4754,7 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( int position, BailoutId assignment_id, HValue* object, - HValue* store_value, - HValue* result_value, + HValue* value, SmallMapList* types, Handle<String> name) { // Use monomorphic store if property lookup results in the same field index @@ -4790,18 +4796,18 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( // Everything matched; can use monomorphic store. BuildCheckHeapObject(object); - Add<HCheckMaps>(object, types); + HCheckMaps* checked_object = Add<HCheckMaps>(object, types); HInstruction* store; CHECK_ALIVE_OR_RETURN( store = BuildStoreNamedField( - object, name, store_value, types->at(count - 1), &lookup), + checked_object, name, value, types->at(count - 1), &lookup), true); - if (!ast_context()->IsEffect()) Push(result_value); + if (!ast_context()->IsEffect()) Push(value); store->set_position(position); AddInstruction(store); Add<HSimulate>(assignment_id); if (!ast_context()->IsEffect()) Drop(1); - ast_context()->ReturnValue(result_value); + ast_context()->ReturnValue(value); return true; } @@ -4810,13 +4816,11 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( int position, BailoutId assignment_id, HValue* object, - HValue* store_value, - HValue* result_value, + HValue* value, SmallMapList* types, Handle<String> name) { if (TryStorePolymorphicAsMonomorphic( - position, assignment_id, object, - store_value, result_value, types, name)) { + position, assignment_id, object, value, types, name)) { return; } @@ -4843,11 +4847,11 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( set_current_block(if_true); HInstruction* instr; CHECK_ALIVE(instr = BuildStoreNamedField( - object, name, store_value, map, &lookup)); + compare, name, value, map, &lookup)); instr->set_position(position); // Goto will add the HSimulate for the store. AddInstruction(instr); - if (!ast_context()->IsEffect()) Push(result_value); + if (!ast_context()->IsEffect()) Push(value); current_block()->Goto(join); set_current_block(if_false); @@ -4860,13 +4864,13 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( if (count == types->length() && FLAG_deoptimize_uncommon_cases) { FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join); } else { - HInstruction* instr = BuildStoreNamedGeneric(object, name, store_value); + HInstruction* instr = BuildStoreNamedGeneric(object, name, value); instr->set_position(position); AddInstruction(instr); if (join != NULL) { if (!ast_context()->IsEffect()) { - Push(result_value); + Push(value); } current_block()->Goto(join); } else { @@ -4877,12 +4881,12 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( if (ast_context()->IsEffect()) { Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); } else { - Push(result_value); + Push(value); Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); Drop(1); } } - return ast_context()->ReturnValue(result_value); + return ast_context()->ReturnValue(value); } } @@ -4895,40 +4899,111 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( } -void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { - Property* prop = expr->target()->AsProperty(); - ASSERT(prop != NULL); - CHECK_ALIVE(VisitForValue(prop->obj())); +static bool ComputeReceiverTypes(Expression* expr, + HValue* receiver, + SmallMapList** t) { + SmallMapList* types = expr->GetReceiverTypes(); + *t = types; + bool monomorphic = expr->IsMonomorphic(); + if (types != NULL && receiver->HasMonomorphicJSObjectType()) { + Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); + types->FilterForPossibleTransitions(root_map); + monomorphic = types->length() == 1; + } + return monomorphic && CanInlinePropertyAccess(*types->first()); +} - if (prop->key()->IsPropertyName()) { - // Named store. - CHECK_ALIVE(VisitForValue(expr->value())); - HValue* value = environment()->ExpressionStackAt(0); - HValue* object = environment()->ExpressionStackAt(1); - if (expr->IsUninitialized()) { - Add<HDeoptimize>("Insufficient type feedback for property assignment", - Deoptimizer::SOFT); - } - return BuildStoreNamed(expr, expr->id(), expr->position(), - expr->AssignmentId(), prop, object, value, value); - } else { +void HOptimizedGraphBuilder::BuildStore(Expression* expr, + Property* prop, + BailoutId ast_id, + BailoutId return_id, + bool is_uninitialized) { + HValue* value = environment()->ExpressionStackAt(0); + + if (!prop->key()->IsPropertyName()) { // Keyed store. - CHECK_ALIVE(VisitForValue(prop->key())); - CHECK_ALIVE(VisitForValue(expr->value())); - HValue* value = environment()->ExpressionStackAt(0); HValue* key = environment()->ExpressionStackAt(1); HValue* object = environment()->ExpressionStackAt(2); bool has_side_effects = false; - HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(), + HandleKeyedElementAccess(object, key, value, expr, return_id, expr->position(), true, // is_store &has_side_effects); Drop(3); Push(value); - Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); + Add<HSimulate>(return_id, REMOVABLE_SIMULATE); return ast_context()->ReturnValue(Pop()); } + + // Named store. + HValue* object = environment()->ExpressionStackAt(1); + + if (is_uninitialized) { + Add<HDeoptimize>("Insufficient type feedback for property assignment", + Deoptimizer::SOFT); + } + + Literal* key = prop->key()->AsLiteral(); + Handle<String> name = Handle<String>::cast(key->value()); + ASSERT(!name.is_null()); + + HInstruction* instr = NULL; + + SmallMapList* types; + bool monomorphic = ComputeReceiverTypes(expr, object, &types); + + if (monomorphic) { + Handle<Map> map = types->first(); + Handle<JSFunction> setter; + Handle<JSObject> holder; + if (LookupSetter(map, name, &setter, &holder)) { + AddCheckConstantFunction(holder, object, map); + if (FLAG_inline_accessors && + TryInlineSetter(setter, ast_id, return_id, value)) { + return; + } + Drop(2); + Add<HPushArgument>(object); + Add<HPushArgument>(value); + instr = new(zone()) HCallConstantFunction(setter, 2); + } else { + Drop(2); + CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, + name, + value, + map)); + } + } else if (types != NULL && types->length() > 1) { + Drop(2); + return HandlePolymorphicStoreNamedField( + expr->position(), ast_id, object, value, types, name); + } else { + Drop(2); + instr = BuildStoreNamedGeneric(object, name, value); + } + + if (!ast_context()->IsEffect()) Push(value); + instr->set_position(expr->position()); + AddInstruction(instr); + if (instr->HasObservableSideEffects()) { + Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); + } + if (!ast_context()->IsEffect()) Drop(1); + return ast_context()->ReturnValue(value); +} + + +void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { + Property* prop = expr->target()->AsProperty(); + ASSERT(prop != NULL); + CHECK_ALIVE(VisitForValue(prop->obj())); + if (!prop->key()->IsPropertyName()) { + CHECK_ALIVE(VisitForValue(prop->key())); + } + CHECK_ALIVE(VisitForValue(expr->value())); + BuildStore(expr, prop, expr->id(), + expr->AssignmentId(), expr->IsUninitialized()); } @@ -4977,70 +5052,6 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( } -void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, - BailoutId id, - int position, - BailoutId assignment_id, - Property* prop, - HValue* object, - HValue* store_value, - HValue* result_value) { - Literal* key = prop->key()->AsLiteral(); - Handle<String> name = Handle<String>::cast(key->value()); - ASSERT(!name.is_null()); - - HInstruction* instr = NULL; - SmallMapList* types = expr->GetReceiverTypes(); - bool monomorphic = expr->IsMonomorphic(); - Handle<Map> map; - if (monomorphic) { - map = types->first(); - if (map->is_dictionary_map()) monomorphic = false; - } - if (monomorphic) { - Handle<JSFunction> setter; - Handle<JSObject> holder; - if (LookupSetter(map, name, &setter, &holder)) { - AddCheckConstantFunction(holder, object, map); - // Don't try to inline if the result_value is different from the - // store_value. That case isn't handled yet by the inlining. - if (result_value == store_value && - FLAG_inline_accessors && - TryInlineSetter(setter, id, assignment_id, store_value)) { - return; - } - Drop(2); - Add<HPushArgument>(object); - Add<HPushArgument>(store_value); - instr = new(zone()) HCallConstantFunction(setter, 2); - } else { - Drop(2); - CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, - name, - store_value, - map)); - } - } else if (types != NULL && types->length() > 1) { - Drop(2); - return HandlePolymorphicStoreNamedField( - position, id, object, - store_value, result_value, types, name); - } else { - Drop(2); - instr = BuildStoreNamedGeneric(object, name, store_value); - } - - if (!ast_context()->IsEffect()) Push(result_value); - instr->set_position(position); - AddInstruction(instr); - if (instr->HasObservableSideEffects()) { - Add<HSimulate>(id, REMOVABLE_SIMULATE); - } - if (!ast_context()->IsEffect()) Drop(1); - return ast_context()->ReturnValue(result_value); -} - - void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { Expression* target = expr->target(); VariableProxy* proxy = target->AsVariableProxy(); @@ -5122,89 +5133,30 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { return ast_context()->ReturnValue(Pop()); } else if (prop != NULL) { - if (prop->key()->IsPropertyName()) { - // Named property. - CHECK_ALIVE(VisitForValue(prop->obj())); - HValue* object = Top(); - - Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); - Handle<Map> map; - HInstruction* load = NULL; - SmallMapList* types = prop->GetReceiverTypes(); - bool monomorphic = prop->IsMonomorphic(); - if (monomorphic) { - map = types->first(); - // We can't generate code for a monomorphic dict mode load so - // just pretend it is not monomorphic. - if (map->is_dictionary_map()) monomorphic = false; - } - if (monomorphic) { - Handle<JSFunction> getter; - Handle<JSObject> holder; - if (LookupGetter(map, name, &getter, &holder)) { - load = BuildCallGetter(object, map, getter, holder); - } else { - load = BuildLoadNamedMonomorphic(object, name, prop, map); - } - } else if (types != NULL && types->length() > 1) { - load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name); - } - if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop); - PushAndAdd(load); - if (load->HasObservableSideEffects()) { - Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); - } - - CHECK_ALIVE(VisitForValue(expr->value())); - HValue* right = Pop(); - HValue* left = Pop(); - - HInstruction* instr = BuildBinaryOperation(operation, left, right); - PushAndAdd(instr); - if (instr->HasObservableSideEffects()) { - Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); - } - - return BuildStoreNamed(expr, expr->id(), expr->position(), - expr->AssignmentId(), prop, object, instr, instr); - } else { - // Keyed property. - CHECK_ALIVE(VisitForValue(prop->obj())); + CHECK_ALIVE(VisitForValue(prop->obj())); + HValue* object = Top(); + HValue* key = NULL; + if ((!prop->IsStringLength() && + !prop->IsFunctionPrototype() && + !prop->key()->IsPropertyName()) || + prop->IsStringAccess()) { CHECK_ALIVE(VisitForValue(prop->key())); - HValue* obj = environment()->ExpressionStackAt(1); - HValue* key = environment()->ExpressionStackAt(0); - - bool has_side_effects = false; - HValue* load = HandleKeyedElementAccess( - obj, key, NULL, prop, prop->LoadId(), RelocInfo::kNoPosition, - false, // is_store - &has_side_effects); - Push(load); - if (has_side_effects) Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); - - CHECK_ALIVE(VisitForValue(expr->value())); - HValue* right = Pop(); - HValue* left = Pop(); - - HInstruction* instr = BuildBinaryOperation(operation, left, right); - PushAndAdd(instr); - if (instr->HasObservableSideEffects()) { - Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); - } + key = Top(); + } - HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(), - RelocInfo::kNoPosition, - true, // is_store - &has_side_effects); + CHECK_ALIVE(PushLoad(prop, object, key, expr->position())); - // Drop the simulated receiver, key, and value. Return the value. - Drop(3); - Push(instr); - ASSERT(has_side_effects); // Stores always have side effects. - Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); - return ast_context()->ReturnValue(Pop()); - } + CHECK_ALIVE(VisitForValue(expr->value())); + HValue* right = Pop(); + HValue* left = Pop(); + HInstruction* instr = BuildBinaryOperation(operation, left, right); + PushAndAdd(instr); + if (instr->HasObservableSideEffects()) { + Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); + } + BuildStore(expr, prop, expr->id(), + expr->AssignmentId(), expr->IsUninitialized()); } else { return Bailout(kInvalidLhsInCompoundAssignment); } @@ -5361,32 +5313,29 @@ void HOptimizedGraphBuilder::VisitThrow(Throw* expr) { HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, - HObjectAccess access, - HValue* typecheck) { + HObjectAccess access) { if (FLAG_track_double_fields && access.representation().IsDouble()) { // load the heap number HLoadNamedField* heap_number = Add<HLoadNamedField>( object, access.WithRepresentation(Representation::Tagged())); heap_number->set_type(HType::HeapNumber()); // load the double value from it - return New<HLoadNamedField>(heap_number, - HObjectAccess::ForHeapNumberValue(), - typecheck); + return New<HLoadNamedField>( + heap_number, HObjectAccess::ForHeapNumberValue()); } - return New<HLoadNamedField>(object, access, typecheck); + return New<HLoadNamedField>(object, access); } HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* object, - HValue* typecheck) { + HValue* checked_string) { if (FLAG_fold_constants && object->IsConstant()) { HConstant* constant = HConstant::cast(object); if (constant->HasStringValue()) { return New<HConstant>(constant->StringValue()->length()); } } - return BuildLoadNamedField( - object, HObjectAccess::ForStringLength(), typecheck); + return BuildLoadNamedField(checked_string, HObjectAccess::ForStringLength()); } @@ -5395,7 +5344,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( Handle<String> name, Property* expr) { if (expr->IsUninitialized()) { - Add<HDeoptimize>("Insufficient feedback for generic named load", + Add<HDeoptimize>("Insufficient type feedback for generic named load", Deoptimizer::SOFT); } HValue* context = environment()->context(); @@ -5417,7 +5366,6 @@ HInstruction* HOptimizedGraphBuilder::BuildCallGetter( HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( HValue* object, Handle<String> name, - Property* expr, Handle<Map> map) { // Handle a load from a known field. ASSERT(!map->is_dictionary_map()); @@ -5425,18 +5373,19 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( // Handle access to various length properties if (name->Equals(isolate()->heap()->length_string())) { if (map->instance_type() == JS_ARRAY_TYPE) { - HCheckMaps* type_check = AddCheckMap(object, map); - return New<HLoadNamedField>(object, - HObjectAccess::ForArrayLength(map->elements_kind()), type_check); + HCheckMaps* checked_object = AddCheckMap(object, map); + return New<HLoadNamedField>( + checked_object, HObjectAccess::ForArrayLength(map->elements_kind())); } } LookupResult lookup(isolate()); map->LookupDescriptor(NULL, *name, &lookup); if (lookup.IsField()) { - HCheckMaps* type_check = AddCheckMap(object, map); - return BuildLoadNamedField(object, - HObjectAccess::ForField(map, &lookup, name), type_check); + HCheckMaps* checked_object = AddCheckMap(object, map); + ASSERT(map->IsJSObjectMap()); + return BuildLoadNamedField( + checked_object, HObjectAccess::ForField(map, &lookup, name)); } // Handle a load of a constant known function. @@ -5446,17 +5395,22 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( return New<HConstant>(constant); } + if (lookup.IsFound()) { + // Cannot handle the property, do a generic load instead. + HValue* context = environment()->context(); + return new(zone()) HLoadNamedGeneric(context, object, name); + } + // Handle a load from a known field somewhere in the prototype 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()); - HCheckMaps* type_check = AddCheckMap(object, map); - BuildCheckPrototypeMaps(prototype, holder); - HValue* holder_value = Add<HConstant>(holder); - return BuildLoadNamedField(holder_value, - HObjectAccess::ForField(holder_map, &lookup, name), type_check); + AddCheckMap(object, map); + HValue* checked_holder = BuildCheckPrototypeMaps(prototype, holder); + return BuildLoadNamedField( + checked_holder, HObjectAccess::ForField(holder_map, &lookup, name)); } // Handle a load of a constant function somewhere in the prototype chain. @@ -5471,7 +5425,8 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( } // No luck, do a generic load. - return BuildLoadNamedGeneric(object, name, expr); + HValue* context = environment()->context(); + return new(zone()) HLoadNamedGeneric(context, object, name); } @@ -5482,19 +5437,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, } -HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( - HValue* object, - HValue* key, - HValue* val, - HValue* dependency, - Handle<Map> map, - bool is_store, - KeyedAccessStoreMode store_mode) { - HCheckMaps* mapcheck = Add<HCheckMaps>(object, map, top_info(), dependency); - if (dependency) { - mapcheck->ClearGVNFlag(kDependsOnElementsKind); - } - +LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { // Loads from a "stock" fast holey double arrays can elide the hole check. LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; if (*map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS) && @@ -5506,10 +5449,30 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( graph()->MarkDependsOnEmptyArrayProtoElements(); } + return load_mode; +} + + +HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( + HValue* object, + HValue* key, + HValue* val, + HValue* dependency, + Handle<Map> map, + bool is_store, + KeyedAccessStoreMode store_mode) { + HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(), + dependency); + if (dependency) { + checked_object->ClearGVNFlag(kDependsOnElementsKind); + } + + LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); return BuildUncheckedMonomorphicElementAccess( - object, key, val, - mapcheck, map->instance_type() == JS_ARRAY_TYPE, - map->elements_kind(), is_store, load_mode, store_mode); + checked_object, key, val, + map->instance_type() == JS_ARRAY_TYPE, + map->elements_kind(), is_store, + load_mode, store_mode); } @@ -5530,6 +5493,7 @@ HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( Handle<Map> most_general_consolidated_map; for (int i = 0; i < maps->length(); ++i) { Handle<Map> map = maps->at(i); + if (!map->IsJSObjectMap()) return NULL; // Don't allow mixing of JSArrays with JSObjects. if (map->instance_type() == JS_ARRAY_TYPE) { if (has_non_js_array_access) return NULL; @@ -5563,14 +5527,14 @@ HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( } if (!has_double_maps && !has_smi_or_object_maps) return NULL; - HCheckMaps* check_maps = Add<HCheckMaps>(object, maps); + HCheckMaps* checked_object = Add<HCheckMaps>(object, maps); // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS. // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS. ElementsKind consolidated_elements_kind = has_seen_holey_elements ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind()) : most_general_consolidated_map->elements_kind(); HInstruction* instr = BuildUncheckedMonomorphicElementAccess( - object, key, val, check_maps, + checked_object, key, val, most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, consolidated_elements_kind, false, NEVER_RETURN_HOLE, STANDARD_STORE); @@ -5582,7 +5546,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( HValue* object, HValue* key, HValue* val, - Expression* prop, + SmallMapList* maps, BailoutId ast_id, int position, bool is_store, @@ -5590,7 +5554,6 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( bool* has_side_effects) { *has_side_effects = false; BuildCheckHeapObject(object); - SmallMapList* maps = prop->GetReceiverTypes(); if (!is_store) { HInstruction* consolidated_load = @@ -5646,7 +5609,8 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( if (untransitionable_maps.length() == 1) { Handle<Map> untransitionable_map = untransitionable_maps[0]; HInstruction* instr = NULL; - if (untransitionable_map->has_slow_elements_kind()) { + if (untransitionable_map->has_slow_elements_kind() || + !untransitionable_map->IsJSObjectMap()) { instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) : BuildLoadKeyedGeneric(object, key)); } else { @@ -5659,14 +5623,11 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( return is_store ? NULL : instr; } - HInstruction* checkspec = - AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); HBasicBlock* join = graph()->CreateBasicBlock(); - HInstruction* elements = AddLoadElements(object, checkspec); - for (int i = 0; i < untransitionable_maps.length(); ++i) { Handle<Map> map = untransitionable_maps[i]; + if (!map->IsJSObjectMap()) continue; ElementsKind elements_kind = map->elements_kind(); HBasicBlock* this_map = graph()->CreateBasicBlock(); HBasicBlock* other_map = graph()->CreateBasicBlock(); @@ -5675,40 +5636,22 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( current_block()->Finish(mapcompare); set_current_block(this_map); - HInstruction* checked_key = NULL; HInstruction* access = NULL; - if (IsFastElementsKind(elements_kind)) { - if (is_store && !IsFastDoubleElementsKind(elements_kind)) { - Add<HCheckMaps>( - elements, isolate()->factory()->fixed_array_map(), - top_info(), mapcompare); - } - if (map->instance_type() == JS_ARRAY_TYPE) { - HInstruction* length = Add<HLoadNamedField>( - object, HObjectAccess::ForArrayLength(elements_kind), mapcompare); - checked_key = Add<HBoundsCheck>(key, length); - } else { - HInstruction* length = AddLoadFixedArrayLength(elements); - checked_key = Add<HBoundsCheck>(key, length); - } - access = AddFastElementAccess( - elements, checked_key, val, mapcompare, - elements_kind, is_store, NEVER_RETURN_HOLE, STANDARD_STORE); - } else if (IsDictionaryElementsKind(elements_kind)) { - if (is_store) { - access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); - } else { - access = AddInstruction(BuildLoadKeyedGeneric(object, key)); - } + if (IsDictionaryElementsKind(elements_kind)) { + access = is_store + ? AddInstruction(BuildStoreKeyedGeneric(object, key, val)) + : AddInstruction(BuildLoadKeyedGeneric(object, key)); } else { - ASSERT(IsExternalArrayElementsKind(elements_kind)); - HInstruction* length = AddLoadFixedArrayLength(elements); - checked_key = Add<HBoundsCheck>(key, length); - HLoadExternalArrayPointer* external_elements = - Add<HLoadExternalArrayPointer>(elements); - access = AddExternalArrayElementAccess( - external_elements, checked_key, val, - mapcompare, elements_kind, is_store); + ASSERT(IsFastElementsKind(elements_kind) || + IsExternalArrayElementsKind(elements_kind)); + LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); + // Happily, mapcompare is a checked object. + access = BuildUncheckedMonomorphicElementAccess( + mapcompare, key, val, + map->instance_type() == JS_ARRAY_TYPE, + elements_kind, is_store, + load_mode, + store_mode); } *has_side_effects |= access->HasObservableSideEffects(); // The caller will use has_side_effects and add a correct Simulate. @@ -5724,7 +5667,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( // Deopt if none of the cases matched. NoObservableSideEffectsScope scope(this); - FinishExitWithHardDeoptimization("Unknown type in polymorphic element access", + FinishExitWithHardDeoptimization("Unknown map in polymorphic element access", join); set_current_block(join); return is_store ? NULL : Pop(); @@ -5742,8 +5685,12 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( bool* has_side_effects) { ASSERT(!expr->IsPropertyName()); HInstruction* instr = NULL; - if (expr->IsMonomorphic()) { - Handle<Map> map = expr->GetMonomorphicReceiverType(); + + SmallMapList* types; + bool monomorphic = ComputeReceiverTypes(expr, obj, &types); + + if (monomorphic) { + Handle<Map> map = types->first(); if (map->has_slow_elements_kind()) { instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) : BuildLoadKeyedGeneric(obj, key); @@ -5753,21 +5700,20 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( instr = BuildMonomorphicElementAccess( obj, key, val, NULL, map, is_store, expr->GetStoreMode()); } - } else if (expr->GetReceiverTypes() != NULL && - !expr->GetReceiverTypes()->is_empty()) { + } else if (types != NULL && !types->is_empty()) { return HandlePolymorphicElementAccess( - obj, key, val, expr, ast_id, position, is_store, + obj, key, val, types, ast_id, position, is_store, expr->GetStoreMode(), has_side_effects); } else { if (is_store) { if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) { - Add<HDeoptimize>("Insufficient feedback for keyed store", + Add<HDeoptimize>("Insufficient type feedback for keyed store", Deoptimizer::SOFT); } instr = BuildStoreKeyedGeneric(obj, key, val); } else { if (expr->AsProperty()->IsUninitialized()) { - Add<HDeoptimize>("Insufficient feedback for keyed load", + Add<HDeoptimize>("Insufficient type feedback for keyed load", Deoptimizer::SOFT); } instr = BuildLoadKeyedGeneric(obj, key); @@ -5846,8 +5792,7 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) { } } else { Push(graph()->GetArgumentsObject()); - VisitForValue(expr->key()); - if (HasStackOverflow() || current_block() == NULL) return true; + CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true); HValue* key = Pop(); Drop(1); // Arguments object. if (function_state()->outer() == NULL) { @@ -5872,15 +5817,20 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) { } -void HOptimizedGraphBuilder::VisitProperty(Property* expr) { - ASSERT(!HasStackOverflow()); - ASSERT(current_block() != NULL); - ASSERT(current_block()->HasPredecessor()); - - if (TryArgumentsAccess(expr)) return; +void HOptimizedGraphBuilder::PushLoad(Property* expr, + HValue* object, + HValue* key, + int position) { + ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); + Push(object); + if (key != NULL) Push(key); + BuildLoad(expr, position, expr->LoadId()); +} - CHECK_ALIVE(VisitForValue(expr->obj())); +void HOptimizedGraphBuilder::BuildLoad(Property* expr, + int position, + BailoutId ast_id) { HInstruction* instr = NULL; if (expr->IsStringLength()) { HValue* string = Pop(); @@ -5889,7 +5839,6 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { AddInstruction(HCheckInstanceType::NewIsString(string, zone())); instr = BuildLoadStringLength(string, checkstring); } else if (expr->IsStringAccess()) { - CHECK_ALIVE(VisitForValue(expr->key())); HValue* index = Pop(); HValue* string = Pop(); HValue* context = environment()->context(); @@ -5905,86 +5854,105 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { } else if (expr->key()->IsPropertyName()) { Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); - SmallMapList* types = expr->GetReceiverTypes(); HValue* object = Top(); - Handle<Map> map; - bool monomorphic = false; - if (expr->IsMonomorphic()) { - map = types->first(); - monomorphic = !map->is_dictionary_map(); - } else if (object->HasMonomorphicJSObjectType()) { - map = object->GetMonomorphicJSObjectMap(); - monomorphic = !map->is_dictionary_map(); - } + SmallMapList* types; + bool monomorphic = ComputeReceiverTypes(expr, object, &types); + if (monomorphic) { + Handle<Map> map = types->first(); Handle<JSFunction> getter; Handle<JSObject> holder; if (LookupGetter(map, name, &getter, &holder)) { AddCheckConstantFunction(holder, Top(), map); - if (FLAG_inline_accessors && TryInlineGetter(getter, expr)) return; + if (FLAG_inline_accessors && + TryInlineGetter(getter, ast_id, expr->LoadId())) { + return; + } Add<HPushArgument>(Pop()); instr = new(zone()) HCallConstantFunction(getter, 1); } else { - instr = BuildLoadNamedMonomorphic(Pop(), name, expr, map); + instr = BuildLoadNamedMonomorphic(Pop(), name, map); } } else if (types != NULL && types->length() > 1) { - return HandlePolymorphicLoadNamedField(expr, Pop(), types, name); + return HandlePolymorphicLoadNamedField( + position, ast_id, Pop(), types, name); } else { instr = BuildLoadNamedGeneric(Pop(), name, expr); } } else { - CHECK_ALIVE(VisitForValue(expr->key())); - HValue* key = Pop(); HValue* obj = Pop(); bool has_side_effects = false; HValue* load = HandleKeyedElementAccess( - obj, key, NULL, expr, expr->id(), expr->position(), + obj, key, NULL, expr, ast_id, position, false, // is_store &has_side_effects); if (has_side_effects) { if (ast_context()->IsEffect()) { - Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); + Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); } else { Push(load); - Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); + Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); Drop(1); } } return ast_context()->ReturnValue(load); } - instr->set_position(expr->position()); - return ast_context()->ReturnInstruction(instr, expr->id()); + instr->set_position(position); + return ast_context()->ReturnInstruction(instr, ast_id); } -void HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant, - CompilationInfo* info) { +void HOptimizedGraphBuilder::VisitProperty(Property* expr) { + ASSERT(!HasStackOverflow()); + ASSERT(current_block() != NULL); + ASSERT(current_block()->HasPredecessor()); + + if (TryArgumentsAccess(expr)) return; + + CHECK_ALIVE(VisitForValue(expr->obj())); + if ((!expr->IsStringLength() && + !expr->IsFunctionPrototype() && + !expr->key()->IsPropertyName()) || + expr->IsStringAccess()) { + CHECK_ALIVE(VisitForValue(expr->key())); + } + + BuildLoad(expr, expr->position(), expr->id()); +} + + +HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant, + CompilationInfo* info) { HConstant* constant_value = New<HConstant>(constant); if (constant->map()->CanOmitMapChecks()) { constant->map()->AddDependentCompilationInfo( DependentCode::kPrototypeCheckGroup, info); - return; + return constant_value; } AddInstruction(constant_value); HCheckMaps* check = Add<HCheckMaps>(constant_value, handle(constant->map()), info); check->ClearGVNFlag(kDependsOnElementsKind); + return check; } -void HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, - Handle<JSObject> holder) { - BuildConstantMapCheck(prototype, top_info()); +HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, + Handle<JSObject> holder) { while (!prototype.is_identical_to(holder)) { - prototype = handle(JSObject::cast(prototype->GetPrototype())); BuildConstantMapCheck(prototype, top_info()); + prototype = handle(JSObject::cast(prototype->GetPrototype())); } + + HInstruction* checked_object = BuildConstantMapCheck(prototype, top_info()); + if (!checked_object->IsLinked()) AddInstruction(checked_object); + return checked_object; } @@ -6384,7 +6352,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind, return false; } AstProperties::Flags* flags(function->flags()); - if (flags->Contains(kDontInline) || flags->Contains(kDontOptimize)) { + if (flags->Contains(kDontInline) || function->dont_optimize()) { TraceInline(target, caller, "target contains unsupported syntax [late]"); return false; } @@ -6630,13 +6598,14 @@ bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, - Property* prop) { + BailoutId ast_id, + BailoutId return_id) { return TryInline(CALL_AS_METHOD, getter, 0, NULL, - prop->id(), - prop->LoadId(), + ast_id, + return_id, GETTER_CALL_RETURN); } @@ -6810,8 +6779,6 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( } else if (exponent == 2.0) { result = HMul::New(zone(), context, left, left); } - } else if (right->EqualsInteger32Constant(2)) { - result = HMul::New(zone(), context, left, left); } if (result == NULL) { @@ -6893,14 +6860,12 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; // Found pattern f.apply(receiver, arguments). - VisitForValue(prop->obj()); - if (HasStackOverflow() || current_block() == NULL) return true; + CHECK_ALIVE_OR_RETURN(VisitForValue(prop->obj()), true); HValue* function = Top(); AddCheckConstantFunction(expr->holder(), function, function_map); Drop(1); - VisitForValue(args->at(0)); - if (HasStackOverflow() || current_block() == NULL) return true; + CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); HValue* receiver = Pop(); if (function_state()->outer() == NULL) { @@ -6931,7 +6896,8 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { Handle<JSFunction> known_function; if (function->IsConstant()) { HConstant* constant_function = HConstant::cast(function); - known_function = Handle<JSFunction>::cast(constant_function->handle()); + known_function = Handle<JSFunction>::cast( + constant_function->handle(isolate())); int args_count = arguments_count - 1; // Excluding receiver. if (TryInlineApply(known_function, expr, args_count)) return true; } @@ -6993,23 +6959,19 @@ void HOptimizedGraphBuilder::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()); - bool monomorphic = expr->IsMonomorphic(); - Handle<Map> receiver_map; - if (monomorphic) { - receiver_map = (types == NULL || types->is_empty()) - ? Handle<Map>::null() - : types->first(); + SmallMapList* types; + bool was_monomorphic = expr->IsMonomorphic(); + bool monomorphic = ComputeReceiverTypes(expr, receiver, &types); + if (!was_monomorphic && monomorphic) { + monomorphic = expr->ComputeTarget(types->first(), name); } - HValue* receiver = - environment()->ExpressionStackAt(expr->arguments()->length()); if (monomorphic) { - if (TryInlineBuiltinMethodCall(expr, - receiver, - receiver_map, - expr->check_type())) { + Handle<Map> map = types->first(); + if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) { if (FLAG_trace_inlining) { PrintF("Inlining builtin "); expr->target()->ShortPrint(); @@ -7027,7 +6989,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { call = PreProcessCall( new(zone()) HCallNamed(context, name, argument_count)); } else { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map); + AddCheckConstantFunction(expr->holder(), receiver, map); if (TryInlineCall(expr)) return; call = PreProcessCall( @@ -7075,7 +7037,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { CHECK_ALIVE(VisitForValue(expr->expression())); HValue* function = Pop(); - Add<HCheckFunction>(function, expr->target()); + Add<HCheckValue>(function, expr->target()); // Replace the global object with the global receiver. HGlobalReceiver* global_receiver = Add<HGlobalReceiver>(global_object); @@ -7127,7 +7089,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { HGlobalReceiver* receiver = New<HGlobalReceiver>(global); PushAndAdd(receiver); CHECK_ALIVE(VisitExpressions(expr->arguments())); - Add<HCheckFunction>(function, expr->target()); + Add<HCheckValue>(function, expr->target()); if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function. if (FLAG_trace_inlining) { @@ -7190,7 +7152,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { HValue* function = Top(); CHECK_ALIVE(VisitExpressions(expr->arguments())); Handle<JSFunction> constructor = expr->target(); - HValue* check = Add<HCheckFunction>(function, constructor); + HValue* check = Add<HCheckValue>(function, constructor); // Force completion of inobject slack tracking before generating // allocation code to finalize instance size. @@ -7279,10 +7241,10 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { CHECK_ALIVE(VisitArgument(expr->expression())); HValue* constructor = HPushArgument::cast(Top())->argument(); CHECK_ALIVE(VisitArgumentList(expr->arguments())); - HCallNew* call; + HBinaryCall* call; if (expr->target().is_identical_to(array_function)) { Handle<Cell> cell = expr->allocation_info_cell(); - Add<HCheckFunction>(constructor, array_function); + Add<HCheckValue>(constructor, array_function); call = new(zone()) HCallNewArray(context, constructor, argument_count, cell, expr->elements_kind()); } else { @@ -7490,13 +7452,33 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement( HConstant* delta = (expr->op() == Token::INC) ? graph()->GetConstant1() : graph()->GetConstantMinus1(); - HInstruction* instr = Add<HAdd>(Top(), delta); + HInstruction* instr = AddUncasted<HAdd>(Top(), delta); + if (instr->IsAdd()) { + HAdd* add = HAdd::cast(instr); + add->set_observed_input_representation(1, rep); + add->set_observed_input_representation(2, Representation::Smi()); + } instr->SetFlag(HInstruction::kCannotBeTagged); instr->ClearAllSideEffects(); return instr; } +void HOptimizedGraphBuilder::BuildStoreForEffect(Expression* expr, + Property* prop, + BailoutId ast_id, + BailoutId return_id, + HValue* object, + HValue* key, + HValue* value) { + EffectContext for_effect(this); + Push(object); + if (key != NULL) Push(key); + Push(value); + BuildStore(expr, prop, ast_id, return_id); +} + + void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); @@ -7573,86 +7555,42 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { return Bailout(kLookupVariableInCountOperation); } - } else { - // Argument of the count operation is a property. - ASSERT(prop != NULL); - - if (prop->key()->IsPropertyName()) { - // Named property. - if (returns_original_input) Push(graph()->GetConstantUndefined()); - - CHECK_ALIVE(VisitForValue(prop->obj())); - HValue* object = Top(); - - Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); - Handle<Map> map; - HInstruction* load = NULL; - bool monomorphic = prop->IsMonomorphic(); - SmallMapList* types = prop->GetReceiverTypes(); - if (monomorphic) { - map = types->first(); - if (map->is_dictionary_map()) monomorphic = false; - } - if (monomorphic) { - Handle<JSFunction> getter; - Handle<JSObject> holder; - if (LookupGetter(map, name, &getter, &holder)) { - load = BuildCallGetter(object, map, getter, holder); - } else { - load = BuildLoadNamedMonomorphic(object, name, prop, map); - } - } else if (types != NULL && types->length() > 1) { - load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name); - } - if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop); - PushAndAdd(load); - if (load->HasObservableSideEffects()) { - Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); - } + Drop(returns_original_input ? 2 : 1); + return ast_context()->ReturnValue(expr->is_postfix() ? input : after); + } - after = BuildIncrement(returns_original_input, expr); - HValue* result = returns_original_input ? Pop() : after; + // Argument of the count operation is a property. + ASSERT(prop != NULL); + if (returns_original_input) Push(graph()->GetConstantUndefined()); - return BuildStoreNamed(expr, expr->id(), expr->position(), - expr->AssignmentId(), prop, object, after, result); - } else { - // Keyed property. - if (returns_original_input) Push(graph()->GetConstantUndefined()); + CHECK_ALIVE(VisitForValue(prop->obj())); + HValue* object = Top(); - CHECK_ALIVE(VisitForValue(prop->obj())); - CHECK_ALIVE(VisitForValue(prop->key())); - HValue* obj = environment()->ExpressionStackAt(1); - HValue* key = environment()->ExpressionStackAt(0); - - bool has_side_effects = false; - HValue* load = HandleKeyedElementAccess( - obj, key, NULL, prop, prop->LoadId(), RelocInfo::kNoPosition, - false, // is_store - &has_side_effects); - Push(load); - if (has_side_effects) Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); - - after = BuildIncrement(returns_original_input, expr); - input = environment()->ExpressionStackAt(0); - - HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(), - RelocInfo::kNoPosition, - true, // is_store - &has_side_effects); - - // Drop the key and the original value from the bailout environment. - // Overwrite the receiver with the result of the operation, and the - // placeholder with the original value if necessary. - Drop(2); - environment()->SetExpressionStackAt(0, after); - if (returns_original_input) environment()->SetExpressionStackAt(1, input); - ASSERT(has_side_effects); // Stores always have side effects. - Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); - } + HValue* key = NULL; + if ((!prop->IsStringLength() && + !prop->IsFunctionPrototype() && + !prop->key()->IsPropertyName()) || + prop->IsStringAccess()) { + CHECK_ALIVE(VisitForValue(prop->key())); + key = Top(); } - Drop(returns_original_input ? 2 : 1); - return ast_context()->ReturnValue(expr->is_postfix() ? input : after); + CHECK_ALIVE(PushLoad(prop, object, key, expr->position())); + + after = BuildIncrement(returns_original_input, expr); + + if (returns_original_input) { + input = Pop(); + // Drop object and key to push it again in the effect context below. + Drop(key == NULL ? 1 : 2); + environment()->SetExpressionStackAt(0, input); + CHECK_ALIVE(BuildStoreForEffect( + expr, prop, expr->id(), expr->AssignmentId(), object, key, after)); + return ast_context()->ReturnValue(Pop()); + } + + environment()->SetExpressionStackAt(0, after); + return BuildStore(expr, prop, expr->id(), expr->AssignmentId()); } @@ -7775,13 +7713,13 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( } if (left_type->Is(Type::None())) { - Add<HDeoptimize>("Insufficient type feedback for left side", + Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", Deoptimizer::SOFT); // TODO(rossberg): we should be able to get rid of non-continuous defaults. left_type = handle(Type::Any(), isolate()); } if (right_type->Is(Type::None())) { - Add<HDeoptimize>("Insufficient type feedback for right side", + Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", Deoptimizer::SOFT); right_type = handle(Type::Any(), isolate()); } @@ -8014,12 +7952,15 @@ void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, } -static bool IsLiteralCompareBool(HValue* left, +static bool IsLiteralCompareBool(Isolate* isolate, + HValue* left, Token::Value op, HValue* right) { return op == Token::EQ_STRICT && - ((left->IsConstant() && HConstant::cast(left)->handle()->IsBoolean()) || - (right->IsConstant() && HConstant::cast(right)->handle()->IsBoolean())); + ((left->IsConstant() && + HConstant::cast(left)->handle(isolate)->IsBoolean()) || + (right->IsConstant() && + HConstant::cast(right)->handle(isolate)->IsBoolean())); } @@ -8071,7 +8012,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { HValue* left = Pop(); Token::Value op = expr->op(); - if (IsLiteralCompareBool(left, op, right)) { + if (IsLiteralCompareBool(isolate(), left, op, right)) { HCompareObjectEqAndBranch* result = New<HCompareObjectEqAndBranch>(left, right); result->set_position(expr->position()); @@ -8109,7 +8050,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { result->set_position(expr->position()); return ast_context()->ReturnInstruction(result, expr->id()); } else { - Add<HCheckFunction>(right, target); + Add<HCheckValue>(right, target); HInstanceOfKnownGlobal* result = new(zone()) HInstanceOfKnownGlobal(context, left, target); result->set_position(expr->position()); @@ -8132,7 +8073,8 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { // Cases handled below depend on collected type feedback. They should // soft deoptimize when there is no type feedback. if (combined_type->Is(Type::None())) { - Add<HDeoptimize>("insufficient type feedback for combined type", + Add<HDeoptimize>("Insufficient type feedback for combined type " + "of binary operation", Deoptimizer::SOFT); combined_type = left_type = right_type = handle(Type::Any(), isolate()); } @@ -8202,21 +8144,23 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, ASSERT(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT); CHECK_ALIVE(VisitForValue(sub_expr)); HValue* value = Pop(); - HIfContinuation continuation; if (expr->op() == Token::EQ_STRICT) { - IfBuilder if_nil(this); - if_nil.If<HCompareObjectEqAndBranch>( - value, (nil == kNullValue) ? graph()->GetConstantNull() - : graph()->GetConstantUndefined()); - if_nil.Then(); - if_nil.Else(); - if_nil.CaptureContinuation(&continuation); + HConstant* nil_constant = nil == kNullValue + ? graph()->GetConstantNull() + : graph()->GetConstantUndefined(); + HCompareObjectEqAndBranch* instr = + New<HCompareObjectEqAndBranch>(value, nil_constant); + instr->set_position(expr->position()); + return ast_context()->ReturnControl(instr, expr->id()); + } else { + ASSERT_EQ(Token::EQ, expr->op()); + Handle<Type> type = expr->combined_type()->Is(Type::None()) + ? handle(Type::Any(), isolate_) + : expr->combined_type(); + HIfContinuation continuation; + BuildCompareNil(value, type, expr->position(), &continuation); return ast_context()->ReturnContinuation(&continuation, expr->id()); } - Handle<Type> type = expr->combined_type()->Is(Type::None()) - ? handle(Type::Any(), isolate_) : expr->combined_type(); - BuildCompareNil(value, type, expr->position(), &continuation); - return ast_context()->ReturnContinuation(&continuation, expr->id()); } @@ -8233,160 +8177,88 @@ HInstruction* HOptimizedGraphBuilder::BuildThisFunction() { HInstruction* HOptimizedGraphBuilder::BuildFastLiteral( - HValue* context, Handle<JSObject> boilerplate_object, - Handle<JSObject> original_boilerplate_object, - Handle<Object> allocation_site, - int data_size, - int pointer_size, + Handle<Object> allocation_site_object, AllocationSiteMode mode) { NoObservableSideEffectsScope no_effects(this); - InstanceType instance_type = boilerplate_object->map()->instance_type(); - ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE); - HType type = instance_type == JS_ARRAY_TYPE - ? HType::JSArray() : HType::JSObject(); - HInstruction* target = NULL; - HInstruction* data_target = NULL; - - if (isolate()->heap()->GetPretenureMode() == TENURED) { - if (data_size != 0) { - HValue* size_in_bytes = Add<HConstant>(data_size); - data_target = Add<HAllocate>(size_in_bytes, HType::JSObject(), TENURED, - FIXED_DOUBLE_ARRAY_TYPE); - Handle<Map> free_space_map = isolate()->factory()->free_space_map(); - AddStoreMapConstant(data_target, free_space_map); - HObjectAccess access = - HObjectAccess::ForJSObjectOffset(FreeSpace::kSizeOffset); - Add<HStoreNamedField>(data_target, access, size_in_bytes); - } - if (pointer_size != 0) { - HValue* size_in_bytes = Add<HConstant>(pointer_size); - target = Add<HAllocate>(size_in_bytes, type, TENURED, instance_type); - } - } else { - HValue* size_in_bytes = Add<HConstant>(data_size + pointer_size); - target = Add<HAllocate>(size_in_bytes, type, NOT_TENURED, instance_type); - } - - int offset = 0; - int data_offset = 0; - BuildEmitDeepCopy(boilerplate_object, original_boilerplate_object, - allocation_site, target, &offset, data_target, - &data_offset, mode); - return target; -} + Handle<FixedArrayBase> elements(boilerplate_object->elements()); + int object_size = boilerplate_object->map()->instance_size(); + int object_offset = object_size; -void HOptimizedGraphBuilder::BuildEmitDeepCopy( - Handle<JSObject> boilerplate_object, - Handle<JSObject> original_boilerplate_object, - Handle<Object> allocation_site_object, - HInstruction* target, - int* offset, - HInstruction* data_target, - int* data_offset, - AllocationSiteMode mode) { + InstanceType instance_type = boilerplate_object->map()->instance_type(); bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE && - AllocationSite::CanTrack(boilerplate_object->map()->instance_type()); + AllocationSite::CanTrack(instance_type); // If using allocation sites, then the payload on the site should already // be filled in as a valid (boilerplate) array. ASSERT(!create_allocation_site_info || AllocationSite::cast(*allocation_site_object)->IsLiteralSite()); - HInstruction* allocation_site = NULL; - if (create_allocation_site_info) { - allocation_site = Add<HConstant>(allocation_site_object); + object_size += AllocationMemento::kSize; } - // Only elements backing stores for non-COW arrays need to be copied. - Handle<FixedArrayBase> elements(boilerplate_object->elements()); - Handle<FixedArrayBase> original_elements( - original_boilerplate_object->elements()); - ElementsKind kind = boilerplate_object->map()->elements_kind(); + ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE); + HType type = instance_type == JS_ARRAY_TYPE + ? HType::JSArray() : HType::JSObject(); + HValue* object_size_constant = Add<HConstant>(object_size); + HInstruction* object = Add<HAllocate>(object_size_constant, type, + isolate()->heap()->GetPretenureMode(), instance_type); + + + BuildEmitObjectHeader(boilerplate_object, object); + + if (create_allocation_site_info) { + HInstruction* allocation_site = Add<HConstant>(allocation_site_object); + BuildCreateAllocationMemento(object, object_offset, allocation_site); + } - int object_offset = *offset; - int object_size = boilerplate_object->map()->instance_size(); int elements_size = (elements->length() > 0 && elements->map() != isolate()->heap()->fixed_cow_array_map()) ? elements->Size() : 0; - int elements_offset = 0; - if (data_target != NULL && boilerplate_object->HasFastDoubleElements()) { - elements_offset = *data_offset; - *data_offset += elements_size; - } else { - // Place elements right after this object. - elements_offset = *offset + object_size; - *offset += elements_size; + HInstruction* object_elements = NULL; + if (elements_size > 0) { + HValue* object_elements_size = Add<HConstant>(elements_size); + if (boilerplate_object->HasFastDoubleElements()) { + object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(), + isolate()->heap()->GetPretenureMode(), FIXED_DOUBLE_ARRAY_TYPE); + } else { + object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(), + isolate()->heap()->GetPretenureMode(), FIXED_ARRAY_TYPE); + } } - // Increase the offset so that subsequent objects end up right after this - // object (and it's elements if they are allocated in the same space). - *offset += object_size; + BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements); + // Copy object elements if non-COW. - HValue* object_elements = BuildEmitObjectHeader(boilerplate_object, target, - data_target, object_offset, elements_offset, elements_size); if (object_elements != NULL) { - BuildEmitElements(elements, original_elements, kind, object_elements, - target, offset, data_target, data_offset); + BuildEmitElements(boilerplate_object, elements, object_elements); } // Copy in-object properties. if (boilerplate_object->map()->NumberOfFields() != 0) { - HValue* object_properties = - Add<HInnerAllocatedObject>(target, object_offset); - BuildEmitInObjectProperties(boilerplate_object, original_boilerplate_object, - object_properties, target, offset, data_target, data_offset); - } - - // Create allocation site info. - if (mode == TRACK_ALLOCATION_SITE && - AllocationSite::CanTrack(boilerplate_object->map()->instance_type())) { - elements_offset += AllocationMemento::kSize; - *offset += AllocationMemento::kSize; - BuildCreateAllocationMemento(target, JSArray::kSize, allocation_site); + BuildEmitInObjectProperties(boilerplate_object, object); } + return object; } -HValue* HOptimizedGraphBuilder::BuildEmitObjectHeader( +void HOptimizedGraphBuilder::BuildEmitObjectHeader( Handle<JSObject> boilerplate_object, - HInstruction* target, - HInstruction* data_target, - int object_offset, - int elements_offset, - int elements_size) { + HInstruction* object) { ASSERT(boilerplate_object->properties()->length() == 0); - HValue* result = NULL; - HValue* object_header = Add<HInnerAllocatedObject>(target, object_offset); Handle<Map> boilerplate_object_map(boilerplate_object->map()); - AddStoreMapConstant(object_header, boilerplate_object_map); - - HInstruction* elements; - if (elements_size == 0) { - Handle<Object> elements_field = - Handle<Object>(boilerplate_object->elements(), isolate()); - elements = Add<HConstant>(elements_field); - } else { - if (data_target != NULL && boilerplate_object->HasFastDoubleElements()) { - elements = Add<HInnerAllocatedObject>(data_target, elements_offset); - } else { - elements = Add<HInnerAllocatedObject>(target, elements_offset); - } - result = elements; - } - Add<HStoreNamedField>(object_header, HObjectAccess::ForElementsPointer(), - elements); + AddStoreMapConstant(object, boilerplate_object_map); Handle<Object> properties_field = Handle<Object>(boilerplate_object->properties(), isolate()); ASSERT(*properties_field == isolate()->heap()->empty_fixed_array()); HInstruction* properties = Add<HConstant>(properties_field); HObjectAccess access = HObjectAccess::ForPropertiesPointer(); - Add<HStoreNamedField>(object_header, access, properties); + Add<HStoreNamedField>(object, access, properties); if (boilerplate_object->IsJSArray()) { Handle<JSArray> boilerplate_array = @@ -8396,22 +8268,30 @@ HValue* HOptimizedGraphBuilder::BuildEmitObjectHeader( HInstruction* length = Add<HConstant>(length_field); ASSERT(boilerplate_array->length()->IsSmi()); - Add<HStoreNamedField>(object_header, HObjectAccess::ForArrayLength( + Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength( boilerplate_array->GetElementsKind()), length); } +} - return result; + +void HOptimizedGraphBuilder::BuildInitElementsInObjectHeader( + Handle<JSObject> boilerplate_object, + HInstruction* object, + HInstruction* object_elements) { + ASSERT(boilerplate_object->properties()->length() == 0); + if (object_elements == NULL) { + Handle<Object> elements_field = + Handle<Object>(boilerplate_object->elements(), isolate()); + object_elements = Add<HConstant>(elements_field); + } + Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), + object_elements); } void HOptimizedGraphBuilder::BuildEmitInObjectProperties( Handle<JSObject> boilerplate_object, - Handle<JSObject> original_boilerplate_object, - HValue* object_properties, - HInstruction* target, - int* offset, - HInstruction* data_target, - int* data_offset) { + HInstruction* object) { Handle<DescriptorArray> descriptors( boilerplate_object->map()->instance_descriptors()); int limit = boilerplate_object->map()->NumberOfOwnDescriptors(); @@ -8435,31 +8315,20 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties( if (value->IsJSObject()) { Handle<JSObject> value_object = Handle<JSObject>::cast(value); - Handle<JSObject> original_value_object = Handle<JSObject>::cast( - Handle<Object>(original_boilerplate_object->InObjectPropertyAt(index), - isolate())); - HInstruction* value_instruction = Add<HInnerAllocatedObject>(target, - *offset); - - Add<HStoreNamedField>(object_properties, access, value_instruction); - BuildEmitDeepCopy(value_object, original_value_object, - Handle<Object>::null(), target, - offset, data_target, data_offset, - DONT_TRACK_ALLOCATION_SITE); + HInstruction* result = + BuildFastLiteral(value_object, + Handle<Object>::null(), DONT_TRACK_ALLOCATION_SITE); + Add<HStoreNamedField>(object, access, result); } else { Representation representation = details.representation(); HInstruction* value_instruction = Add<HConstant>(value); if (representation.IsDouble()) { // Allocate a HeapNumber box and store the value into it. - HInstruction* double_box; - if (data_target != NULL) { - double_box = Add<HInnerAllocatedObject>(data_target, *data_offset); - *data_offset += HeapNumber::kSize; - } else { - double_box = Add<HInnerAllocatedObject>(target, *offset); - *offset += HeapNumber::kSize; - } + HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize); + HInstruction* double_box = + Add<HAllocate>(heap_number_constant, HType::HeapNumber(), + isolate()->heap()->GetPretenureMode(), HEAP_NUMBER_TYPE); AddStoreMapConstant(double_box, isolate()->factory()->heap_number_map()); Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(), @@ -8467,7 +8336,7 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties( value_instruction = double_box; } - Add<HStoreNamedField>(object_properties, access, value_instruction); + Add<HStoreNamedField>(object, access, value_instruction); } } @@ -8478,31 +8347,25 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties( ASSERT(boilerplate_object->IsJSObject()); int property_offset = boilerplate_object->GetInObjectPropertyOffset(i); HObjectAccess access = HObjectAccess::ForJSObjectOffset(property_offset); - Add<HStoreNamedField>(object_properties, access, value_instruction); + Add<HStoreNamedField>(object, access, value_instruction); } } void HOptimizedGraphBuilder::BuildEmitElements( + Handle<JSObject> boilerplate_object, Handle<FixedArrayBase> elements, - Handle<FixedArrayBase> original_elements, - ElementsKind kind, - HValue* object_elements, - HInstruction* target, - int* offset, - HInstruction* data_target, - int* data_offset) { + HValue* object_elements) { + ElementsKind kind = boilerplate_object->map()->elements_kind(); int elements_length = elements->length(); HValue* object_elements_length = Add<HConstant>(elements_length); - BuildInitializeElementsHeader(object_elements, kind, object_elements_length); // Copy elements backing store content. if (elements->IsFixedDoubleArray()) { BuildEmitFixedDoubleArray(elements, kind, object_elements); } else if (elements->IsFixedArray()) { - BuildEmitFixedArray(elements, original_elements, kind, object_elements, - target, offset, data_target, data_offset); + BuildEmitFixedArray(elements, kind, object_elements); } else { UNREACHABLE(); } @@ -8530,32 +8393,20 @@ void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray( void HOptimizedGraphBuilder::BuildEmitFixedArray( Handle<FixedArrayBase> elements, - Handle<FixedArrayBase> original_elements, ElementsKind kind, - HValue* object_elements, - HInstruction* target, - int* offset, - HInstruction* data_target, - int* data_offset) { + HValue* object_elements) { HInstruction* boilerplate_elements = Add<HConstant>(elements); int elements_length = elements->length(); Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); - Handle<FixedArray> original_fast_elements = - Handle<FixedArray>::cast(original_elements); for (int i = 0; i < elements_length; i++) { Handle<Object> value(fast_elements->get(i), isolate()); HValue* key_constant = Add<HConstant>(i); if (value->IsJSObject()) { Handle<JSObject> value_object = Handle<JSObject>::cast(value); - Handle<JSObject> original_value_object = Handle<JSObject>::cast( - Handle<Object>(original_fast_elements->get(i), isolate())); - HInstruction* value_instruction = Add<HInnerAllocatedObject>(target, - *offset); - Add<HStoreKeyed>(object_elements, key_constant, value_instruction, kind); - BuildEmitDeepCopy(value_object, original_value_object, - Handle<Object>::null(), target, - offset, data_target, data_offset, - DONT_TRACK_ALLOCATION_SITE); + HInstruction* result = + BuildFastLiteral(value_object, + Handle<Object>::null(), DONT_TRACK_ALLOCATION_SITE); + Add<HStoreKeyed>(object_elements, key_constant, result, kind); } else { HInstruction* value_instruction = Add<HLoadKeyed>(boilerplate_elements, key_constant, @@ -9555,7 +9406,7 @@ void HTracer::TraceCompilation(CompilationInfo* info) { void HTracer::TraceLithium(const char* name, LChunk* chunk) { - ASSERT(!FLAG_parallel_recompilation); + ASSERT(!FLAG_concurrent_recompilation); AllowHandleDereference allow_deref; AllowDeferredHandleDereference allow_deferred_deref; Trace(name, chunk->graph(), chunk); @@ -9563,7 +9414,7 @@ void HTracer::TraceLithium(const char* name, LChunk* chunk) { void HTracer::TraceHydrogen(const char* name, HGraph* graph) { - ASSERT(!FLAG_parallel_recompilation); + ASSERT(!FLAG_concurrent_recompilation); AllowHandleDereference allow_deref; AllowDeferredHandleDereference allow_deferred_deref; Trace(name, graph, NULL); @@ -9773,15 +9624,15 @@ void HStatistics::Initialize(CompilationInfo* info) { void HStatistics::Print() { PrintF("Timing results:\n"); - int64_t sum = 0; - for (int i = 0; i < timing_.length(); ++i) { - sum += timing_[i]; + TimeDelta sum; + for (int i = 0; i < times_.length(); ++i) { + sum += times_[i]; } for (int i = 0; i < names_.length(); ++i) { PrintF("%32s", names_[i]); - double ms = static_cast<double>(timing_[i]) / 1000; - double percent = static_cast<double>(timing_[i]) * 100 / sum; + double ms = times_[i].InMillisecondsF(); + double percent = times_[i].PercentOf(sum); PrintF(" %8.3f ms / %4.1f %% ", ms, percent); unsigned size = sizes_[i]; @@ -9791,29 +9642,29 @@ void HStatistics::Print() { PrintF("----------------------------------------" "---------------------------------------\n"); - int64_t total = create_graph_ + optimize_graph_ + generate_code_; + TimeDelta total = create_graph_ + optimize_graph_ + generate_code_; PrintF("%32s %8.3f ms / %4.1f %% \n", "Create graph", - static_cast<double>(create_graph_) / 1000, - static_cast<double>(create_graph_) * 100 / total); + create_graph_.InMillisecondsF(), + create_graph_.PercentOf(total)); PrintF("%32s %8.3f ms / %4.1f %% \n", "Optimize graph", - static_cast<double>(optimize_graph_) / 1000, - static_cast<double>(optimize_graph_) * 100 / total); + optimize_graph_.InMillisecondsF(), + optimize_graph_.PercentOf(total)); PrintF("%32s %8.3f ms / %4.1f %% \n", "Generate and install code", - static_cast<double>(generate_code_) / 1000, - static_cast<double>(generate_code_) * 100 / total); + generate_code_.InMillisecondsF(), + generate_code_.PercentOf(total)); PrintF("----------------------------------------" "---------------------------------------\n"); PrintF("%32s %8.3f ms (%.1f times slower than full code gen)\n", "Total", - static_cast<double>(total) / 1000, - static_cast<double>(total) / full_code_gen_); + total.InMillisecondsF(), + total.TimesOf(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>(total) / 1000) / source_size_in_kb + ? total.InMillisecondsF() / source_size_in_kb : 0; double normalized_size_in_kb = source_size_in_kb > 0 ? total_size_ / 1024 / source_size_in_kb @@ -9824,17 +9675,17 @@ void HStatistics::Print() { } -void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) { +void HStatistics::SaveTiming(const char* name, TimeDelta time, unsigned size) { total_size_ += size; for (int i = 0; i < names_.length(); ++i) { if (strcmp(names_[i], name) == 0) { - timing_[i] += ticks; + times_[i] += time; sizes_[i] += size; return; } } names_.Add(name); - timing_.Add(ticks); + times_.Add(time); sizes_.Add(size); } |