Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(117)

Unified Diff: src/compiler/js-call-reducer.cc

Issue 2803853005: Inline Array.prototype.forEach in TurboFan (Closed)
Patch Set: fix v8heapconst.py Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/compiler/js-call-reducer.cc
diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc
index 1e1d3a92ab01abc235b58dbec165db4ad3d83ecb..9a9c1e282bafeaedc36f4d62facd232538cf6d01 100644
--- a/src/compiler/js-call-reducer.cc
+++ b/src/compiler/js-call-reducer.cc
@@ -7,6 +7,7 @@
#include "src/code-factory.h"
#include "src/code-stubs.h"
#include "src/compilation-dependencies.h"
+#include "src/compiler/access-builder.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
@@ -350,6 +351,134 @@ Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) {
return ReduceObjectGetPrototype(node, target);
}
+Reduction JSCallReducer::ReduceArrayForEach(Handle<SharedFunctionInfo> shared,
+ Node* node) {
+ if (!FLAG_inline_array_builtins) return NoChange();
+ DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
+ Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ Node* context = NodeProperties::GetContextInput(node);
+ CallParameters const& p = CallParametersOf(node->op());
+
+ // Try to determine the {receiver} map.
+ Node* receiver = NodeProperties::GetValueInput(node, 1);
+ Node* fncallback = node->op()->ValueInputCount() > 2
+ ? NodeProperties::GetValueInput(node, 2)
+ : jsgraph()->UndefinedConstant();
+ Node* this_arg = node->op()->ValueInputCount() > 3
+ ? NodeProperties::GetValueInput(node, 3)
+ : jsgraph()->UndefinedConstant();
+ ZoneHandleSet<Map> receiver_maps;
+ if (!NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps)) {
Benedikt Meurer 2017/05/22 19:29:40 This returns an enum. You only want to deal with r
danno 2017/06/06 12:04:52 Done.
+ return NoChange();
+ }
+ if (receiver_maps.size() != 1) return NoChange();
+ Handle<Map> receiver_map(receiver_maps[0]);
+ ElementsKind kind = receiver_map->elements_kind();
+ // TODO(danno): Handle holey Smi and Object fast elements kinds and double
+ // packed.
+ if (!IsFastPackedElementsKind(kind) || IsFastDoubleElementsKind(kind)) {
+ return NoChange();
+ }
+
+ Node* k = jsgraph()->Constant(0);
Jarin 2017/05/24 06:41:22 a.k.a. ZeroConstant()
danno 2017/06/06 12:04:52 Done.
+
+ Node* original_length = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)),
+ receiver, effect, control);
+
+ Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
+ Node* eloop = effect =
+ graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
+ Node* vloop = k = graph()->NewNode(
+ common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
+
+ control = loop;
+ effect = eloop;
+
+ Node* continue_test =
+ graph()->NewNode(simplified()->NumberLessThan(), k, original_length);
+ Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
+ continue_test, control);
+
+ Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch);
+ Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch);
+ control = if_true;
+
+ std::vector<Node*> checkpoint_params(
+ {receiver, fncallback, this_arg, k, original_length});
+ const int stack_parameters = static_cast<int>(checkpoint_params.size());
+
+ Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
+ jsgraph(), shared, Builtins::kArrayForEachLoopEagerDeoptContinuation,
+ node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
+ outer_frame_state, ContinuationFrameStateMode::EAGER);
+
+ effect =
+ graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
+
+ // Make sure the map hasn't changed during the iteration
+ Node* orig_map = jsgraph()->HeapConstant(receiver_map);
+ Node* array_map = effect =
+ graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
+ receiver, effect, control);
+ Node* check_map =
+ graph()->NewNode(simplified()->ReferenceEqual(), array_map, orig_map);
+ effect =
+ graph()->NewNode(simplified()->CheckIf(), check_map, effect, control);
+
+ // Make sure that the access is still in bounds, since the callback could have
+ // changed the array's size.
+ Node* length = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)),
+ receiver, effect, control);
+ k = effect =
+ graph()->NewNode(simplified()->CheckBounds(), k, length, effect, control);
+ USE(length);
Benedikt Meurer 2017/05/22 19:29:40 This is unnecessary.
danno 2017/06/06 12:04:52 Done.
+
+ // Reload the elements pointer before calling the callback, since the previous
+ // callback might have resized the array causing the elements buffer to be
+ // re-allocated.
+ Node* elements = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
+ effect, control);
+
+ Node* element = graph()->NewNode(
+ simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
+ elements, k, effect, control);
+
+ Node* next_k =
+ graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->Constant(1));
+ checkpoint_params[3] = next_k;
+ frame_state = CreateJavaScriptBuiltinContinuationFrameState(
+ jsgraph(), shared, Builtins::kArrayForEachLoopLazyDeoptContinuation,
+ node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
+ outer_frame_state, ContinuationFrameStateMode::LAZY);
+
+ Node* call_back = control = effect = graph()->NewNode(
+ javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
Benedikt Meurer 2017/05/22 19:29:40 This doesn't properly rewire IfException edges. Ca
danno 2017/06/06 12:04:52 Done.
+ receiver, context, frame_state, effect, control);
+ USE(call_back);
Benedikt Meurer 2017/05/22 19:29:40 You don't seem to need the call_back variable.
danno 2017/06/06 12:04:52 Done.
+ USE(this_arg);
Benedikt Meurer 2017/05/22 19:29:40 This is unnecessary.
danno 2017/06/06 12:04:52 Done.
+
+ k = next_k;
+
+ loop->ReplaceInput(1, control);
+ vloop->ReplaceInput(1, k);
+ eloop->ReplaceInput(1, effect);
+
+ control = if_false;
+ effect = eloop;
+
+ NodeProperties::ReplaceUses(node, jsgraph()->UndefinedConstant(), effect,
Benedikt Meurer 2017/05/22 19:29:40 Can you use ReplaceWithValue instead of this magic
Michael Starzinger 2017/05/24 13:54:59 +1, otherwise we might run into similar issues as
danno 2017/06/06 12:04:52 Done.
danno 2017/06/06 12:04:52 Done.
+ control);
+
+ node->TrimInputCount(0);
+ NodeProperties::ChangeOp(node, common()->Dead());
+ return Changed(node);
+}
+
Reduction JSCallReducer::ReduceCallApiFunction(
Node* node, Handle<FunctionTemplateInfo> function_template_info) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
@@ -616,6 +745,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return ReduceObjectPrototypeGetProto(node);
case Builtins::kReflectGetPrototypeOf:
return ReduceReflectGetPrototypeOf(node);
+ case Builtins::kArrayForEach:
+ return ReduceArrayForEach(shared, node);
default:
break;
}

Powered by Google App Engine
This is Rietveld 408576698