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
parent 4abd57dc
......@@ -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<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);
......@@ -5673,19 +5665,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)
......@@ -5704,113 +5692,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);
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(if_true);
HInstruction* access;
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(), 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);
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, checked_key, val, mapcompare,
elements_kind, is_store, NEVER_RETURN_HOLE, STANDARD_STORE));
} else if (elements_kind == DICTIONARY_ELEMENTS) {
} else if (IsDictionaryElementsKind(elements_kind)) {
if (is_store) {
access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
} else {
access = AddInstruction(BuildLoadKeyedGeneric(object, key));
}
} else { // External array elements.
} 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,
elements_kind_branch, elements_kind, is_store));
mapcompare, elements_kind, is_store));
}
*has_side_effects |= access->HasObservableSideEffects();
// The caller will use has_side_effects and add correct Simulate.
// 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(if_false);
}
set_current_block(other_map);
}
// Deopt if none of the cases matched.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment