[ic] Completely unroll polymorphic IC map checks

Polymorphic IC feedback can contain up to four (map, handler) pairs.

HandlePolymorphicCase already unrolled checks for the first two pairs; these
are guaranteed to exist and can omit bound checks.

This CL unrolls checks against the final two pairs as well.

BUG=v8:5917

Review-Url: https://codereview.chromium.org/2728293005
Cr-Commit-Position: refs/heads/master@{#43650}
This commit is contained in:
jgruber 2017-03-07 08:57:07 -08:00 committed by Commit bot
parent c478a2298d
commit 3c246db781
4 changed files with 32 additions and 10 deletions

View File

@ -8,6 +8,7 @@
#include "src/code-stubs.h" #include "src/code-stubs.h"
#include "src/counters.h" #include "src/counters.h"
#include "src/ic/handler-configuration.h" #include "src/ic/handler-configuration.h"
#include "src/ic/ic.h"
#include "src/ic/stub-cache.h" #include "src/ic/stub-cache.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
@ -57,7 +58,7 @@ void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
Node* feedback, Label* if_handler, Node* feedback, Label* if_handler,
Variable* var_handler, Variable* var_handler,
Label* if_miss, Label* if_miss,
int unroll_count) { int min_feedback_capacity) {
Comment("HandlePolymorphicCase"); Comment("HandlePolymorphicCase");
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep()); DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
@ -68,14 +69,31 @@ void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
// Iterate {feedback} array. // Iterate {feedback} array.
const int kEntrySize = 2; const int kEntrySize = 2;
for (int i = 0; i < unroll_count; i++) { // Loading feedback's length is delayed until we need it when looking past
// the first {min_feedback_capacity} (map, handler) pairs.
Node* length = nullptr;
CSA_ASSERT(this, SmiGreaterThanOrEqual(
LoadFixedArrayBaseLength(feedback),
SmiConstant(min_feedback_capacity * kEntrySize)));
const int kUnrolledIterations = IC::kMaxPolymorphicMapCount;
for (int i = 0; i < kUnrolledIterations; i++) {
int map_index = i * kEntrySize;
int handler_index = i * kEntrySize + 1;
if (i >= min_feedback_capacity) {
if (length == nullptr) length = LoadFixedArrayBaseLength(feedback);
GotoIf(SmiGreaterThanOrEqual(SmiConstant(handler_index), length),
if_miss);
}
Label next_entry(this); Label next_entry(this);
Node* cached_map = Node* cached_map =
LoadWeakCellValue(LoadFixedArrayElement(feedback, i * kEntrySize)); LoadWeakCellValue(LoadFixedArrayElement(feedback, map_index));
GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry); GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
// Found, now call handler. // Found, now call handler.
Node* handler = LoadFixedArrayElement(feedback, i * kEntrySize + 1); Node* handler = LoadFixedArrayElement(feedback, handler_index);
var_handler->Bind(handler); var_handler->Bind(handler);
Goto(if_handler); Goto(if_handler);
@ -83,12 +101,12 @@ void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
} }
Goto(&loop); Goto(&loop);
// Loop from {unroll_count}*kEntrySize to {length}. // Loop from {kUnrolledIterations}*kEntrySize to {length}.
Bind(&loop); Bind(&loop);
Node* init = IntPtrConstant(unroll_count * kEntrySize); Node* start_index = IntPtrConstant(kUnrolledIterations * kEntrySize);
Node* length = LoadAndUntagFixedArrayBaseLength(feedback); Node* end_index = LoadAndUntagFixedArrayBaseLength(feedback);
BuildFastLoop( BuildFastLoop(
init, length, start_index, end_index,
[this, receiver_map, feedback, if_handler, var_handler](Node* index) { [this, receiver_map, feedback, if_handler, var_handler](Node* index) {
Node* cached_map = Node* cached_map =
LoadWeakCellValue(LoadFixedArrayElement(feedback, index)); LoadWeakCellValue(LoadFixedArrayElement(feedback, index));

View File

@ -123,7 +123,7 @@ class AccessorAssembler : public CodeStubAssembler {
Label* if_miss); Label* if_miss);
void HandlePolymorphicCase(Node* receiver_map, Node* feedback, void HandlePolymorphicCase(Node* receiver_map, Node* feedback,
Label* if_handler, Variable* var_handler, Label* if_handler, Variable* var_handler,
Label* if_miss, int unroll_count); Label* if_miss, int min_feedback_capacity);
void HandleKeyedStorePolymorphicCase(Node* receiver_map, Node* feedback, void HandleKeyedStorePolymorphicCase(Node* receiver_map, Node* feedback,
Label* if_handler, Variable* var_handler, Label* if_handler, Variable* var_handler,
Label* if_transition_handler, Label* if_transition_handler,

View File

@ -771,7 +771,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) {
int number_of_valid_maps = int number_of_valid_maps =
number_of_maps - deprecated_maps - (handler_to_overwrite != -1); number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
if (number_of_valid_maps >= 4) return false; if (number_of_valid_maps >= kMaxPolymorphicMapCount) return false;
if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) { if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
return false; return false;
} }

View File

@ -26,6 +26,10 @@ class IC {
// or with a single extra frame for supporting calls. // or with a single extra frame for supporting calls.
enum FrameDepth { NO_EXTRA_FRAME = 0, EXTRA_CALL_FRAME = 1 }; enum FrameDepth { NO_EXTRA_FRAME = 0, EXTRA_CALL_FRAME = 1 };
// A polymorphic IC can handle at most 4 distinct maps before transitioning
// to megamorphic state.
static constexpr int kMaxPolymorphicMapCount = 4;
// Construct the IC structure with the given number of extra // Construct the IC structure with the given number of extra
// JavaScript frames on the stack. // JavaScript frames on the stack.
IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL); IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL);