Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index f6588bcc2d37c58cdc4023a69af3dadcca7c9ae6..e369be7bb6773c87e059286a62e0f437d97989a8 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -3337,7 +3337,42 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), |
Representation::Integer32())); |
if (FLAG_smi_only_arrays) { |
+ HInstruction* elements_kind = |
+ AddInstruction(new(zone()) HElementsKind(literal)); |
+ HBasicBlock* store_fast = graph()->CreateBasicBlock(); |
danno
2011/09/23 09:05:24
Wow, cool, you went for bonus points here (I don't
Jakob Kummerow
2011/09/26 11:30:32
Done.
|
+ // Two empty blocks to satisfy edge split form. |
+ HBasicBlock* store_fast_edgesplit1 = graph()->CreateBasicBlock(); |
+ HBasicBlock* store_fast_edgesplit2 = graph()->CreateBasicBlock(); |
+ HBasicBlock* store_generic = graph()->CreateBasicBlock(); |
+ HBasicBlock* check_smi_only_elements = graph()->CreateBasicBlock(); |
+ HBasicBlock* join = graph()->CreateBasicBlock(); |
+ |
+ HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(value); |
+ smicheck->SetSuccessorAt(0, store_fast_edgesplit1); |
+ smicheck->SetSuccessorAt(1, check_smi_only_elements); |
+ current_block()->Finish(smicheck); |
+ store_fast_edgesplit1->Finish(new(zone()) HGoto(store_fast)); |
+ |
+ set_current_block(check_smi_only_elements); |
+ HCompareConstantEqAndBranch* smi_elements_check = |
+ new(zone()) HCompareConstantEqAndBranch(elements_kind, |
+ FAST_SMI_ONLY_ELEMENTS, |
+ Token::EQ_STRICT); |
+ smi_elements_check->SetSuccessorAt(0, store_generic); |
+ smi_elements_check->SetSuccessorAt(1, store_fast_edgesplit2); |
+ current_block()->Finish(smi_elements_check); |
+ store_fast_edgesplit2->Finish(new(zone()) HGoto(store_fast)); |
+ |
+ set_current_block(store_fast); |
+ AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); |
+ store_fast->Goto(join); |
+ |
+ set_current_block(store_generic); |
AddInstruction(BuildStoreKeyedGeneric(literal, key, value)); |
+ store_generic->Goto(join); |
+ |
+ join->SetJoinId(expr->id()); |
+ set_current_block(join); |
} else { |
AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); |
} |
@@ -3969,6 +4004,33 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( |
} |
+HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, |
danno
2011/09/23 09:05:24
I find it a little asymmetric that BuildFirstEleme
danno
2011/09/23 09:07:52
"not last last one" should read "the returned inst
Jakob Kummerow
2011/09/26 11:30:32
It's currently consistent with a bunch of other me
|
+ HValue* checked_key, |
+ HValue* val, |
+ ElementsKind elements_kind, |
+ bool is_store) { |
+ if (is_store) { |
+ ASSERT(val != NULL); |
+ if (elements_kind == FAST_DOUBLE_ELEMENTS) { |
+ return new(zone()) HStoreKeyedFastDoubleElement( |
+ elements, checked_key, val); |
+ } else if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
+ AddInstruction(new(zone()) HCheckSmi(val)); |
+ return new(zone()) HStoreKeyedFastElement( |
+ elements, checked_key, val, HStoreKeyedFastElement::VALUE_IS_SMI); |
+ } else { |
+ return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); |
+ } |
+ } else { |
+ if (elements_kind == FAST_DOUBLE_ELEMENTS) { |
+ return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); |
+ } else { |
+ return new(zone()) HLoadKeyedFastElement(elements, checked_key); |
danno
2011/09/23 09:05:24
If you're refactoring anyway, perhaps you might wa
Jakob Kummerow
2011/09/26 11:30:32
Done. Removed the unnecessary outer "else" and add
|
+ } |
+ } |
+} |
+ |
+ |
HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
HValue* key, |
HValue* val, |
@@ -3978,15 +4040,18 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
Handle<Map> map = expr->GetMonomorphicReceiverType(); |
AddInstruction(new(zone()) HCheckNonSmi(object)); |
HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); |
- if (!map->has_fast_elements() && |
- !map->has_fast_double_elements() && |
+ bool fast_smi_only_elements = map->has_fast_smi_only_elements(); |
+ bool fast_elements = map->has_fast_elements(); |
+ bool fast_double_elements = map->has_fast_double_elements(); |
+ if (!fast_smi_only_elements && |
+ !fast_elements && |
+ !fast_double_elements && |
!map->has_external_array_elements()) { |
return is_store ? BuildStoreKeyedGeneric(object, key, val) |
: BuildLoadKeyedGeneric(object, key); |
} |
HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
- bool fast_double_elements = map->has_fast_double_elements(); |
- if (is_store && map->has_fast_elements()) { |
+ if (is_store && (fast_elements || fast_smi_only_elements)) { |
AddInstruction(new(zone()) HCheckMap( |
elements, isolate()->factory()->fixed_array_map())); |
} |
@@ -4001,28 +4066,15 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
return BuildExternalArrayElementAccess(external_elements, checked_key, |
val, map->elements_kind(), is_store); |
} |
- ASSERT(map->has_fast_elements() || fast_double_elements); |
+ ASSERT(fast_smi_only_elements || fast_elements || fast_double_elements); |
danno
2011/09/23 09:05:24
Perhaps add predicates to the map that test for mu
Jakob Kummerow
2011/09/26 11:30:32
I'd prefer not to do that, for two reasons:
(1) Th
|
if (map->instance_type() == JS_ARRAY_TYPE) { |
length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck)); |
} else { |
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
} |
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
- if (is_store) { |
- if (fast_double_elements) { |
- return new(zone()) HStoreKeyedFastDoubleElement(elements, |
- checked_key, |
- val); |
- } else { |
- return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); |
- } |
- } else { |
- if (fast_double_elements) { |
- return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); |
- } else { |
- return new(zone()) HLoadKeyedFastElement(elements, checked_key); |
- } |
- } |
+ return BuildFastElementAccess(elements, checked_key, val, |
+ map->elements_kind(), is_store); |
} |
@@ -4075,7 +4127,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; |
elements_kind <= LAST_ELEMENTS_KIND; |
elements_kind = ElementsKind(elements_kind + 1)) { |
- // After having handled FAST_ELEMENTS, FAST_SMI_ELEMENTS, |
+ // After having handled FAST_ELEMENTS, FAST_SMI_ONLY_ELEMENTS, |
// FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code |
// that's executed for all external array cases. |
STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == |
@@ -4102,13 +4154,25 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
if (elements_kind == FAST_SMI_ONLY_ELEMENTS || |
elements_kind == FAST_ELEMENTS || |
elements_kind == FAST_DOUBLE_ELEMENTS) { |
- bool fast_double_elements = |
- elements_kind == FAST_DOUBLE_ELEMENTS; |
- if (is_store && !fast_double_elements) { |
+ if (is_store && elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
+ // When the |object| has FAST_SMI_ONLY_ELEMENTS, chances are we'll |
danno
2011/09/23 09:05:24
stype nit: passive voice instead of "we"?
Jakob Kummerow
2011/09/26 11:30:32
Done -- both comment and the code it referred to a
|
+ // only ever see more Smis being stored in it, so it's fine to |
+ // just deopt if that assumption is ever wrong. |
+ AddInstruction(new(zone()) HCheckSmi(val)); |
+ } |
+ if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) { |
AddInstruction(new(zone()) HCheckMap( |
elements, isolate()->factory()->fixed_array_map(), |
elements_kind_branch)); |
} |
+ // TODO(jkummerow): We could get around the need for these two blocks |
danno
2011/09/23 09:05:24
stype nit: passive voice instead of "we"?
Jakob Kummerow
2011/09/26 11:30:32
Done.
|
+ // 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 = |
@@ -4119,37 +4183,12 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
set_current_block(if_jsarray); |
HInstruction* length; |
- if (is_store && elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
- // For now, fall back to the generic stub for |
- // FAST_SMI_ONLY_ELEMENTS |
- access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); |
- } else { |
- length = new(zone()) HJSArrayLength(object, typecheck); |
- AddInstruction(length); |
- checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
- if (is_store) { |
- if (fast_double_elements) { |
- access = AddInstruction( |
- new(zone()) HStoreKeyedFastDoubleElement(elements, |
- checked_key, |
- val)); |
- } else { |
- access = AddInstruction( |
- new(zone()) HStoreKeyedFastElement(elements, |
- checked_key, |
- val)); |
- } |
- } else { |
- if (fast_double_elements) { |
- access = AddInstruction( |
- new(zone()) HLoadKeyedFastDoubleElement(elements, |
- checked_key)); |
- } else { |
- access = AddInstruction( |
- new(zone()) HLoadKeyedFastElement(elements, checked_key)); |
- } |
- Push(access); |
- } |
+ length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck)); |
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
+ access = AddInstruction(BuildFastElementAccess( |
+ elements, checked_key, val, elements_kind, is_store)); |
+ if (!is_store) { |
+ Push(access); |
} |
*has_side_effects |= access->HasSideEffects(); |
@@ -4161,25 +4200,8 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
set_current_block(if_fastobject); |
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
- if (is_store) { |
- if (fast_double_elements) { |
- access = AddInstruction( |
- new(zone()) HStoreKeyedFastDoubleElement(elements, |
- checked_key, |
- val)); |
- } else { |
- access = AddInstruction( |
- new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); |
- } |
- } else { |
- if (fast_double_elements) { |
- access = AddInstruction( |
- new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key)); |
- } else { |
- access = AddInstruction( |
- new(zone()) HLoadKeyedFastElement(elements, checked_key)); |
- } |
- } |
+ access = AddInstruction(BuildFastElementAccess( |
+ elements, checked_key, val, elements_kind, is_store)); |
} else if (elements_kind == DICTIONARY_ELEMENTS) { |
if (is_store) { |
access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); |