| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index c90e5c5b7e09630f89205b9dbe03ef15312b8cc2..4b8f1636e1691330453dffe6dec0c06bb61966a3 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -5892,7 +5892,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 =
|
| @@ -5906,12 +5905,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.
|
| @@ -5932,8 +5925,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
| transition_target.Add(transitioned_map);
|
| }
|
|
|
| - int num_untransitionable_maps = 0;
|
| - Handle<Map> untransitionable_map;
|
| + MapHandleList untransitionable_maps(maps->length());
|
| HTransitionElementsKind* transition = NULL;
|
| for (int i = 0; i < maps->length(); ++i) {
|
| Handle<Map> map = maps->at(i);
|
| @@ -5946,19 +5938,15 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
| transition = Add<HTransitionElementsKind>(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<Map> untransitionable_map = untransitionable_maps[0];
|
| HInstruction* instr = NULL;
|
| if (untransitionable_map->has_slow_elements_kind()) {
|
| instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val)
|
| @@ -5977,113 +5965,63 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
| AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone()));
|
| HBasicBlock* join = graph()->CreateBasicBlock();
|
|
|
| - HInstruction* elements_kind_instr = Add<HElementsKind>(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<HBoundsCheck>(key, length);
|
| - external_elements = Add<HLoadExternalArrayPointer>(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> 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<HBoundsCheck>(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<HBoundsCheck>(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<HBoundsCheck>(key, length);
|
| + HLoadExternalArrayPointer* external_elements =
|
| + Add<HLoadExternalArrayPointer>(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.
|
|
|