From: jkummerow@chromium.org Date: Thu, 18 Jul 2013 09:46:56 +0000 (+0000) Subject: Hydrogen array accesses: switch from elements_kind to map based polymorphism X-Git-Tag: upstream/4.7.83~13314 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2c7b8cf5c1725630f28096b17bb2a27a001325ac;p=platform%2Fupstream%2Fv8.git Hydrogen array accesses: switch from elements_kind to map based polymorphism R=verwaest@chromium.org Review URL: https://codereview.chromium.org/18209023 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15743 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/hydrogen.cc b/src/hydrogen.cc index f399261..627dec9 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -5619,7 +5619,6 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( *has_side_effects = false; BuildCheckHeapObject(object); SmallMapList* maps = prop->GetReceiverTypes(); - bool todo_external_array = false; if (!is_store) { HInstruction* consolidated_load = @@ -5633,12 +5632,6 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( } } - static const int kNumElementTypes = kElementsKindCount; - bool type_todo[kNumElementTypes]; - for (int i = 0; i < kNumElementTypes; ++i) { - type_todo[i] = false; - } - // Elements_kind transition support. MapHandleList transition_target(maps->length()); // Collect possible transition targets. @@ -5659,8 +5652,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( transition_target.Add(transitioned_map); } - int num_untransitionable_maps = 0; - Handle untransitionable_map; + MapHandleList untransitionable_maps(maps->length()); HTransitionElementsKind* transition = NULL; for (int i = 0; i < maps->length(); ++i) { Handle map = maps->at(i); @@ -5673,19 +5665,15 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( transition = Add(context, object, map, transition_target.at(i)); } else { - type_todo[map->elements_kind()] = true; - if (IsExternalArrayElementsKind(map->elements_kind())) { - todo_external_array = true; - } - num_untransitionable_maps++; - untransitionable_map = map; + untransitionable_maps.Add(map); } } // If only one map is left after transitioning, handle this case // monomorphically. - ASSERT(num_untransitionable_maps >= 1); - if (num_untransitionable_maps == 1) { + ASSERT(untransitionable_maps.length() >= 1); + if (untransitionable_maps.length() == 1) { + Handle untransitionable_map = untransitionable_maps[0]; HInstruction* instr = NULL; if (untransitionable_map->has_slow_elements_kind()) { instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) @@ -5704,113 +5692,63 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); HBasicBlock* join = graph()->CreateBasicBlock(); - HInstruction* elements_kind_instr = Add(object); HInstruction* elements = AddLoadElements(object, checkspec); - HLoadExternalArrayPointer* external_elements = NULL; - HInstruction* checked_key = NULL; - - // Generated code assumes that FAST_* and DICTIONARY_ELEMENTS ElementsKinds - // are handled before external arrays. - STATIC_ASSERT(FAST_SMI_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); - STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); - STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); - STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); - - for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; - elements_kind <= LAST_ELEMENTS_KIND; - elements_kind = ElementsKind(elements_kind + 1)) { - // After having handled FAST_* and DICTIONARY_ELEMENTS, we need to add some - // code that's executed for all external array cases. - STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == - LAST_ELEMENTS_KIND); - if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND - && todo_external_array) { - HInstruction* length = AddLoadFixedArrayLength(elements); - checked_key = Add(key, length); - external_elements = Add(elements); - } - if (type_todo[elements_kind]) { - HBasicBlock* if_true = graph()->CreateBasicBlock(); - HBasicBlock* if_false = graph()->CreateBasicBlock(); - 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); - set_current_block(if_true); - HInstruction* access; - if (IsFastElementsKind(elements_kind)) { - if (is_store && !IsFastDoubleElementsKind(elements_kind)) { - AddInstruction(HCheckMaps::New( - elements, isolate()->factory()->fixed_array_map(), - zone(), elements_kind_branch)); - } - // TODO(jkummerow): The need for these two blocks could be avoided - // in one of two ways: - // (1) Introduce ElementsKinds for JSArrays that are distinct from - // those for fast objects. - // (2) Put the common instructions into a third "join" block. This - // requires additional AST IDs that we can deopt to from inside - // that join block. They must be added to the Property class (when - // it's a keyed property) and registered in the full codegen. - HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); - HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); - HHasInstanceTypeAndBranch* typecheck = - new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); - typecheck->SetSuccessorAt(0, if_jsarray); - typecheck->SetSuccessorAt(1, if_fastobject); - current_block()->Finish(typecheck); - - set_current_block(if_jsarray); + for (int i = 0; i < untransitionable_maps.length(); ++i) { + Handle map = untransitionable_maps[i]; + ElementsKind elements_kind = map->elements_kind(); + HBasicBlock* this_map = graph()->CreateBasicBlock(); + HBasicBlock* other_map = graph()->CreateBasicBlock(); + HCompareMap* mapcompare = + new(zone()) HCompareMap(object, map, this_map, other_map); + 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)) { + AddInstruction(HCheckMaps::New( + elements, isolate()->factory()->fixed_array_map(), + zone(), mapcompare)); + } + if (map->IsJSArray()) { HInstruction* length = AddLoad(object, HObjectAccess::ForArrayLength(), - typecheck, Representation::Smi()); + mapcompare, Representation::Smi()); length->set_type(HType::Smi()); - checked_key = Add(key, length); - access = AddInstruction(BuildFastElementAccess( - elements, checked_key, val, elements_kind_branch, - elements_kind, is_store, NEVER_RETURN_HOLE, STANDARD_STORE)); - if (!is_store) { - Push(access); - } - - *has_side_effects |= access->HasObservableSideEffects(); - // The caller will use has_side_effects and add correct Simulate. - access->SetFlag(HValue::kHasNoObservableSideEffects); - if (position != -1) { - access->set_position(position); - } - if_jsarray->GotoNoSimulate(join); - - set_current_block(if_fastobject); - length = AddLoadFixedArrayLength(elements); + } else { + HInstruction* length = AddLoadFixedArrayLength(elements); checked_key = Add(key, length); - access = AddInstruction(BuildFastElementAccess( - elements, checked_key, val, elements_kind_branch, - elements_kind, is_store, NEVER_RETURN_HOLE, STANDARD_STORE)); - } else if (elements_kind == DICTIONARY_ELEMENTS) { - if (is_store) { - access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); - } else { - access = AddInstruction(BuildLoadKeyedGeneric(object, key)); - } - } else { // External array elements. - access = AddInstruction(BuildExternalArrayElementAccess( - external_elements, checked_key, val, - elements_kind_branch, elements_kind, is_store)); } - *has_side_effects |= access->HasObservableSideEffects(); - // The caller will use has_side_effects and add correct Simulate. - access->SetFlag(HValue::kHasNoObservableSideEffects); - if (position != RelocInfo::kNoPosition) access->set_position(position); - if (!is_store) { - Push(access); + access = AddInstruction(BuildFastElementAccess( + 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)); } - current_block()->GotoNoSimulate(join); - set_current_block(if_false); - } + } else { + ASSERT(IsExternalArrayElementsKind(elements_kind)); + HInstruction* length = AddLoadFixedArrayLength(elements); + checked_key = Add(key, length); + HLoadExternalArrayPointer* external_elements = + Add(elements); + access = AddInstruction(BuildExternalArrayElementAccess( + external_elements, checked_key, val, + mapcompare, elements_kind, is_store)); + } + *has_side_effects |= access->HasObservableSideEffects(); + // The caller will use has_side_effects and add a correct Simulate. + access->SetFlag(HValue::kHasNoObservableSideEffects); + if (position != RelocInfo::kNoPosition) access->set_position(position); + if (!is_store) { + Push(access); + } + current_block()->GotoNoSimulate(join); + set_current_block(other_map); } // Deopt if none of the cases matched.