From: bmeurer@chromium.org Date: Tue, 3 Jun 2014 04:01:34 +0000 (+0000) Subject: Inline fast path for Array.indexOf() and Array.lastIndexOf(). X-Git-Tag: upstream/4.7.83~8863 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2a2874b9c351a17dd3925ef0ccc4d22cec4ed4e0;p=platform%2Fupstream%2Fv8.git Inline fast path for Array.indexOf() and Array.lastIndexOf(). TEST=mjsunit/array-indexing R=mvstanton@chromium.org Review URL: https://codereview.chromium.org/308793012 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21617 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/hydrogen.cc b/src/hydrogen.cc index c836dc2..49fd879 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::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(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( + elements, index, static_cast(NULL), + kind, ALLOW_RETURN_HOLE); + IfBuilder if_issame(this); + if (IsFastDoubleElementsKind(kind)) { + if_issame.If( + element, search_element, Token::EQ_STRICT); + } else { + if_issame.If(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(search_element); + if_isstring.Then(); + { + LoopBuilder loop(this, context(), direction); + { + HValue* index = loop.BeginBody(initial, terminating, token); + HValue* element = AddUncasted( + elements, index, static_cast(NULL), + kind, ALLOW_RETURN_HOLE); + IfBuilder if_issame(this); + if_issame.If(element); + if_issame.AndIf( + 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(search_element); + HCompareMap* isheapnumber = if_isheapnumber.AndIf( + search_element, isolate()->factory()->heap_number_map()); + if_isheapnumber.Then(); + { + HValue* search_number = Add( + search_element, isheapnumber, + HObjectAccess::ForHeapNumberValue()); + LoopBuilder loop(this, context(), direction); + { + HValue* index = loop.BeginBody(initial, terminating, token); + HValue* element = AddUncasted( + elements, index, static_cast(NULL), + kind, ALLOW_RETURN_HOLE); + IfBuilder if_issame(this); + HCompareMap* issame = if_issame.If( + element, isolate()->factory()->heap_number_map()); + if_issame.And(); + HValue* number = Add( + element, issame, HObjectAccess::ForHeapNumberValue()); + if_issame.If( + 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( + elements, index, static_cast(NULL), + kind, ALLOW_RETURN_HOLE); + IfBuilder if_issame(this); + if_issame.If( + 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; diff --git a/src/hydrogen.h b/src/hydrogen.h index bb05ebb..4544bbb 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -2251,6 +2251,12 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { void BuildArrayCall(Expression* expr, int arguments_count, HValue* function, Handle cell); + enum ArrayIndexOfMode { kFirstIndexOf, kLastIndexOf }; + HValue* BuildArrayIndexOf(HValue* receiver, + HValue* search_element, + ElementsKind kind, + ArrayIndexOfMode mode); + HValue* ImplicitReceiverFor(HValue* function, Handle target); diff --git a/src/objects.h b/src/objects.h index ce11a10..9f63657 100644 --- a/src/objects.h +++ b/src/objects.h @@ -6858,24 +6858,26 @@ class Script: public Struct { // // Installation of ids for the selected builtin functions is handled // by the bootstrapper. -#define FUNCTIONS_WITH_ID_LIST(V) \ - V(Array.prototype, push, ArrayPush) \ - V(Array.prototype, pop, ArrayPop) \ - V(Array.prototype, shift, ArrayShift) \ - V(Function.prototype, apply, FunctionApply) \ - V(String.prototype, charCodeAt, StringCharCodeAt) \ - V(String.prototype, charAt, StringCharAt) \ - V(String, fromCharCode, StringFromCharCode) \ - V(Math, floor, MathFloor) \ - V(Math, round, MathRound) \ - V(Math, ceil, MathCeil) \ - V(Math, abs, MathAbs) \ - V(Math, log, MathLog) \ - V(Math, exp, MathExp) \ - V(Math, sqrt, MathSqrt) \ - V(Math, pow, MathPow) \ - V(Math, max, MathMax) \ - V(Math, min, MathMin) \ +#define FUNCTIONS_WITH_ID_LIST(V) \ + V(Array.prototype, indexOf, ArrayIndexOf) \ + V(Array.prototype, lastIndexOf, ArrayLastIndexOf) \ + V(Array.prototype, push, ArrayPush) \ + V(Array.prototype, pop, ArrayPop) \ + V(Array.prototype, shift, ArrayShift) \ + V(Function.prototype, apply, FunctionApply) \ + V(String.prototype, charCodeAt, StringCharCodeAt) \ + V(String.prototype, charAt, StringCharAt) \ + V(String, fromCharCode, StringFromCharCode) \ + V(Math, floor, MathFloor) \ + V(Math, round, MathRound) \ + V(Math, ceil, MathCeil) \ + V(Math, abs, MathAbs) \ + V(Math, log, MathLog) \ + V(Math, exp, MathExp) \ + V(Math, sqrt, MathSqrt) \ + V(Math, pow, MathPow) \ + V(Math, max, MathMax) \ + V(Math, min, MathMin) \ V(Math, imul, MathImul) enum BuiltinFunctionId {