| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index f6588bcc2d37c58cdc4023a69af3dadcca7c9ae6..bfeaaf3ad543597ff7ee95b6af3caa63f0095116 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();
|
| + // 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,30 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
|
| }
|
|
|
|
|
| +HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
|
| + 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 { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS.
|
| + return new(zone()) HStoreKeyedFastElement(
|
| + elements, checked_key, val, elements_kind);
|
| + }
|
| + }
|
| + // It's an element load (!is_store).
|
| + if (elements_kind == FAST_DOUBLE_ELEMENTS) {
|
| + return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key);
|
| + } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS.
|
| + return new(zone()) HLoadKeyedFastElement(elements, checked_key);
|
| + }
|
| +}
|
| +
|
| +
|
| HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
|
| HValue* key,
|
| HValue* val,
|
| @@ -3978,15 +4037,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 +4063,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);
|
| 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 +4124,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 +4151,22 @@ 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) {
|
| + 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): 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 =
|
| @@ -4119,37 +4177,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 +4194,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));
|
|
|