[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:
parent
c478a2298d
commit
3c246db781
@ -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));
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user