| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index c836dc21653129de5d7255a3c8d8b2e9c63e71c0..49fd879bdc4f397062db5cf791668a2658cebf42 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -8032,6 +8032,43 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| ast_context()->ReturnValue(result);
|
| return true;
|
| }
|
| + case kArrayIndexOf:
|
| + case kArrayLastIndexOf: {
|
| + if (receiver_map.is_null()) return false;
|
| + if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
|
| + ElementsKind kind = receiver_map->elements_kind();
|
| + if (!IsFastElementsKind(kind)) return false;
|
| + if (receiver_map->is_observed()) return false;
|
| + if (argument_count != 2) return false;
|
| + ASSERT(receiver_map->is_extensible());
|
| +
|
| + // If there may be elements accessors in the prototype chain, the fast
|
| + // inlined version can't be used.
|
| + if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
|
| +
|
| + // If there currently can be no elements accessors on the prototype chain,
|
| + // it doesn't mean that there won't be any later. Install a full prototype
|
| + // chain check to trap element accessors being installed on the prototype
|
| + // chain, which would cause elements to go to dictionary mode and result
|
| + // in a map change.
|
| + BuildCheckPrototypeMaps(
|
| + handle(JSObject::cast(receiver_map->prototype()), isolate()),
|
| + Handle<JSObject>::null());
|
| +
|
| + HValue* search_element = Pop();
|
| + HValue* receiver = Pop();
|
| + Drop(1); // Drop function.
|
| +
|
| + ArrayIndexOfMode mode = (id == kArrayIndexOf)
|
| + ? kFirstIndexOf : kLastIndexOf;
|
| + HValue* index = BuildArrayIndexOf(receiver, search_element, kind, mode);
|
| +
|
| + if (!ast_context()->IsEffect()) Push(index);
|
| + Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
|
| + if (!ast_context()->IsEffect()) Drop(1);
|
| + ast_context()->ReturnValue(index);
|
| + return true;
|
| + }
|
| default:
|
| // Not yet supported for inlining.
|
| break;
|
| @@ -8324,6 +8361,148 @@ void HOptimizedGraphBuilder::BuildArrayCall(Expression* expression,
|
| }
|
|
|
|
|
| +HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver,
|
| + HValue* search_element,
|
| + ElementsKind kind,
|
| + ArrayIndexOfMode mode) {
|
| + ASSERT(IsFastElementsKind(kind));
|
| +
|
| + NoObservableSideEffectsScope no_effects(this);
|
| +
|
| + HValue* elements = AddLoadElements(receiver);
|
| + HValue* length = AddLoadArrayLength(receiver, kind);
|
| +
|
| + HValue* initial;
|
| + HValue* terminating;
|
| + Token::Value token;
|
| + LoopBuilder::Direction direction;
|
| + if (mode == kFirstIndexOf) {
|
| + initial = graph()->GetConstant0();
|
| + terminating = length;
|
| + token = Token::LT;
|
| + direction = LoopBuilder::kPostIncrement;
|
| + } else {
|
| + ASSERT_EQ(kLastIndexOf, mode);
|
| + initial = length;
|
| + terminating = graph()->GetConstant0();
|
| + token = Token::GTE;
|
| + direction = LoopBuilder::kPreDecrement;
|
| + }
|
| +
|
| + Push(graph()->GetConstantMinus1());
|
| + if (IsFastDoubleElementsKind(kind) || IsFastSmiElementsKind(kind)) {
|
| + LoopBuilder loop(this, context(), direction);
|
| + {
|
| + HValue* index = loop.BeginBody(initial, terminating, token);
|
| + HValue* element = AddUncasted<HLoadKeyed>(
|
| + elements, index, static_cast<HValue*>(NULL),
|
| + kind, ALLOW_RETURN_HOLE);
|
| + IfBuilder if_issame(this);
|
| + if (IsFastDoubleElementsKind(kind)) {
|
| + if_issame.If<HCompareNumericAndBranch>(
|
| + element, search_element, Token::EQ_STRICT);
|
| + } else {
|
| + if_issame.If<HCompareObjectEqAndBranch>(element, search_element);
|
| + }
|
| + if_issame.Then();
|
| + {
|
| + Drop(1);
|
| + Push(index);
|
| + loop.Break();
|
| + }
|
| + if_issame.End();
|
| + }
|
| + loop.EndBody();
|
| + } else {
|
| + IfBuilder if_isstring(this);
|
| + if_isstring.If<HIsStringAndBranch>(search_element);
|
| + if_isstring.Then();
|
| + {
|
| + LoopBuilder loop(this, context(), direction);
|
| + {
|
| + HValue* index = loop.BeginBody(initial, terminating, token);
|
| + HValue* element = AddUncasted<HLoadKeyed>(
|
| + elements, index, static_cast<HValue*>(NULL),
|
| + kind, ALLOW_RETURN_HOLE);
|
| + IfBuilder if_issame(this);
|
| + if_issame.If<HIsStringAndBranch>(element);
|
| + if_issame.AndIf<HStringCompareAndBranch>(
|
| + element, search_element, Token::EQ_STRICT);
|
| + if_issame.Then();
|
| + {
|
| + Drop(1);
|
| + Push(index);
|
| + loop.Break();
|
| + }
|
| + if_issame.End();
|
| + }
|
| + loop.EndBody();
|
| + }
|
| + if_isstring.Else();
|
| + {
|
| + IfBuilder if_isheapnumber(this);
|
| + if_isheapnumber.IfNot<HIsSmiAndBranch>(search_element);
|
| + HCompareMap* isheapnumber = if_isheapnumber.AndIf<HCompareMap>(
|
| + search_element, isolate()->factory()->heap_number_map());
|
| + if_isheapnumber.Then();
|
| + {
|
| + HValue* search_number = Add<HLoadNamedField>(
|
| + search_element, isheapnumber,
|
| + HObjectAccess::ForHeapNumberValue());
|
| + LoopBuilder loop(this, context(), direction);
|
| + {
|
| + HValue* index = loop.BeginBody(initial, terminating, token);
|
| + HValue* element = AddUncasted<HLoadKeyed>(
|
| + elements, index, static_cast<HValue*>(NULL),
|
| + kind, ALLOW_RETURN_HOLE);
|
| + IfBuilder if_issame(this);
|
| + HCompareMap* issame = if_issame.If<HCompareMap>(
|
| + element, isolate()->factory()->heap_number_map());
|
| + if_issame.And();
|
| + HValue* number = Add<HLoadNamedField>(
|
| + element, issame, HObjectAccess::ForHeapNumberValue());
|
| + if_issame.If<HCompareNumericAndBranch>(
|
| + number, search_number, Token::EQ_STRICT);
|
| + if_issame.Then();
|
| + {
|
| + Drop(1);
|
| + Push(index);
|
| + loop.Break();
|
| + }
|
| + if_issame.End();
|
| + }
|
| + loop.EndBody();
|
| + }
|
| + if_isheapnumber.Else();
|
| + {
|
| + LoopBuilder loop(this, context(), direction);
|
| + {
|
| + HValue* index = loop.BeginBody(initial, terminating, token);
|
| + HValue* element = AddUncasted<HLoadKeyed>(
|
| + elements, index, static_cast<HValue*>(NULL),
|
| + kind, ALLOW_RETURN_HOLE);
|
| + IfBuilder if_issame(this);
|
| + if_issame.If<HCompareObjectEqAndBranch>(
|
| + element, search_element);
|
| + if_issame.Then();
|
| + {
|
| + Drop(1);
|
| + Push(index);
|
| + loop.Break();
|
| + }
|
| + if_issame.End();
|
| + }
|
| + loop.EndBody();
|
| + }
|
| + if_isheapnumber.End();
|
| + }
|
| + if_isstring.End();
|
| + }
|
| +
|
| + return Pop();
|
| +}
|
| +
|
| +
|
| bool HOptimizedGraphBuilder::TryHandleArrayCall(Call* expr, HValue* function) {
|
| if (!array_function().is_identical_to(expr->target())) {
|
| return false;
|
|
|