Commit 918b1378 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[nojit] Remove elements kind parameter from two stubs

In preparation for converting these stubs to builtins. This turns
compile-time elements kind parameters into a runtime check, essentially
emitting all contained logic for each elements kinds and dispatching
at runtime.

Bug: v8:7777
Change-Id: I7a5c97ea2775e9f8ff469db6ab577de6c65c6bbe
Reviewed-on: https://chromium-review.googlesource.com/c/1340282
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57714}
parent ac9908a0
......@@ -10387,9 +10387,14 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
// Skip the store if we write beyond the length or
// to a property with a negative integer index.
GotoIfNot(UintPtrLessThan(intptr_key, length), &done);
} else {
DCHECK_EQ(STANDARD_STORE, store_mode);
} else if (store_mode == STANDARD_STORE) {
GotoIfNot(UintPtrLessThan(intptr_key, length), bailout);
} else {
// This case is produced due to the dispatched call in
// ElementsTransitionAndStore and StoreFastElement.
// TODO(jgruber): Avoid generating unsupported combinations to save code
// size.
DebugBreak();
}
if (elements_kind == BIGINT64_ELEMENTS ||
......@@ -10412,8 +10417,7 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
BIND(&done);
return;
}
DCHECK(IsSmiOrObjectElementsKind(elements_kind) ||
IsDoubleElementsKind(elements_kind));
DCHECK(IsFastElementsKind(elements_kind));
Node* length =
SelectImpl(IsJSArray(object), [=]() { return LoadJSArrayLength(object); },
......
......@@ -266,7 +266,97 @@ Handle<Code> TurboFanCodeStub::GenerateCode() {
&state, AssemblerOptions::Default(isolate()));
}
TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) {
namespace {
class HandlerStubAssembler : public CodeStubAssembler {
public:
explicit HandlerStubAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
// Essentially turns runtime elements kinds (TNode<Int32T>) into
// compile-time types (int) by dispatching over the runtime type and
// emitting a specialized copy of the given case function for each elements
// kind. Use with caution. This produces a *lot* of code.
typedef std::function<void(ElementsKind)> ElementsKindSwitchCase;
void DispatchByElementsKind(TNode<Int32T> elements_kind,
const ElementsKindSwitchCase& case_function);
// Dispatches over all possible combinations of {from,to} elements kinds.
typedef std::function<void(ElementsKind, ElementsKind)>
ElementsKindTransitionSwitchCase;
void DispatchForElementsKindTransition(
TNode<Int32T> from_kind, TNode<Int32T> to_kind,
const ElementsKindTransitionSwitchCase& case_function);
};
// All possible fast-to-fast transitions. Transitions to dictionary mode are not
// handled by ElementsTransitionAndStore.
#define ELEMENTS_KIND_TRANSITIONS(V) \
V(PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS) \
V(PACKED_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS) \
V(PACKED_SMI_ELEMENTS, HOLEY_DOUBLE_ELEMENTS) \
V(PACKED_SMI_ELEMENTS, PACKED_ELEMENTS) \
V(PACKED_SMI_ELEMENTS, HOLEY_ELEMENTS) \
V(HOLEY_SMI_ELEMENTS, HOLEY_DOUBLE_ELEMENTS) \
V(HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS) \
V(PACKED_DOUBLE_ELEMENTS, HOLEY_DOUBLE_ELEMENTS) \
V(PACKED_DOUBLE_ELEMENTS, PACKED_ELEMENTS) \
V(PACKED_DOUBLE_ELEMENTS, HOLEY_ELEMENTS) \
V(HOLEY_DOUBLE_ELEMENTS, HOLEY_ELEMENTS) \
V(PACKED_ELEMENTS, HOLEY_ELEMENTS)
void HandlerStubAssembler::DispatchForElementsKindTransition(
TNode<Int32T> from_kind, TNode<Int32T> to_kind,
const ElementsKindTransitionSwitchCase& case_function) {
STATIC_ASSERT(sizeof(ElementsKind) == sizeof(uint8_t));
Label next(this), if_unknown_type(this, Label::kDeferred);
int32_t combined_elements_kinds[] = {
#define ELEMENTS_KINDS_CASE(FROM, TO) (FROM << kBitsPerByte) | TO,
ELEMENTS_KIND_TRANSITIONS(ELEMENTS_KINDS_CASE)
#undef ELEMENTS_KINDS_CASE
};
#define ELEMENTS_KINDS_CASE(FROM, TO) Label if_##FROM##_##TO(this);
ELEMENTS_KIND_TRANSITIONS(ELEMENTS_KINDS_CASE)
#undef ELEMENTS_KINDS_CASE
Label* elements_kind_labels[] = {
#define ELEMENTS_KINDS_CASE(FROM, TO) &if_##FROM##_##TO,
ELEMENTS_KIND_TRANSITIONS(ELEMENTS_KINDS_CASE)
#undef ELEMENTS_KINDS_CASE
};
STATIC_ASSERT(arraysize(combined_elements_kinds) ==
arraysize(elements_kind_labels));
TNode<Word32T> combined_elements_kind =
Word32Or(Word32Shl(from_kind, Int32Constant(kBitsPerByte)), to_kind);
Switch(combined_elements_kind, &if_unknown_type, combined_elements_kinds,
elements_kind_labels, arraysize(combined_elements_kinds));
#define ELEMENTS_KINDS_CASE(FROM, TO) \
BIND(&if_##FROM##_##TO); \
{ \
case_function(FROM, TO); \
Goto(&next); \
}
ELEMENTS_KIND_TRANSITIONS(ELEMENTS_KINDS_CASE)
#undef ELEMENTS_KINDS_CASE
BIND(&if_unknown_type);
Unreachable();
BIND(&next);
}
#undef ELEMENTS_KIND_TRANSITIONS
} // namespace
TF_STUB(ElementsTransitionAndStoreStub, HandlerStubAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver);
Node* key = Parameter(Descriptor::kName);
Node* value = Parameter(Descriptor::kValue);
......@@ -275,10 +365,7 @@ TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) {
Node* vector = Parameter(Descriptor::kVector);
Node* context = Parameter(Descriptor::kContext);
Comment(
"ElementsTransitionAndStoreStub: from_kind=%s, to_kind=%s, store_mode=%d",
ElementsKindToString(stub->from_kind()),
ElementsKindToString(stub->to_kind()), stub->store_mode());
Comment("ElementsTransitionAndStoreStub: store_mode=%d", stub->store_mode());
Label miss(this);
......@@ -286,19 +373,20 @@ TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) {
// Tracing elements transitions is the job of the runtime.
Goto(&miss);
} else {
TransitionElementsKind(receiver, map, stub->from_kind(), stub->to_kind(),
&miss);
EmitElementStore(receiver, key, value, stub->to_kind(), stub->store_mode(),
&miss, context);
// TODO(v8:8481): Pass from_kind and to_kind in feedback vector slots.
DispatchForElementsKindTransition(
LoadElementsKind(receiver), LoadMapElementsKind(map),
[=, &miss](ElementsKind from_kind, ElementsKind to_kind) {
TransitionElementsKind(receiver, map, from_kind, to_kind, &miss);
EmitElementStore(receiver, key, value, to_kind, stub->store_mode(),
&miss, context);
});
Return(value);
}
BIND(&miss);
{
Comment("Miss");
TailCallRuntime(Runtime::kElementsTransitionAndStoreIC_Miss, context,
receiver, key, value, map, slot, vector);
}
TailCallRuntime(Runtime::kElementsTransitionAndStoreIC_Miss, context,
receiver, key, value, map, slot, vector);
}
int JSEntryStub::GenerateHandlerTable(MacroAssembler* masm) {
......@@ -307,9 +395,74 @@ int JSEntryStub::GenerateHandlerTable(MacroAssembler* masm) {
return handler_table_offset;
}
TF_STUB(StoreFastElementStub, CodeStubAssembler) {
Comment("StoreFastElementStub: elements_kind=%s, store_mode=%d",
ElementsKindToString(stub->elements_kind()), stub->store_mode());
namespace {
// All elements kinds handled by EmitElementStore. Specifically, this includes
// fast elements and fixed typed array elements.
#define ELEMENTS_KINDS(V) \
V(PACKED_SMI_ELEMENTS) \
V(HOLEY_SMI_ELEMENTS) \
V(PACKED_ELEMENTS) \
V(HOLEY_ELEMENTS) \
V(PACKED_DOUBLE_ELEMENTS) \
V(HOLEY_DOUBLE_ELEMENTS) \
V(UINT8_ELEMENTS) \
V(INT8_ELEMENTS) \
V(UINT16_ELEMENTS) \
V(INT16_ELEMENTS) \
V(UINT32_ELEMENTS) \
V(INT32_ELEMENTS) \
V(FLOAT32_ELEMENTS) \
V(FLOAT64_ELEMENTS) \
V(UINT8_CLAMPED_ELEMENTS) \
V(BIGUINT64_ELEMENTS) \
V(BIGINT64_ELEMENTS)
void HandlerStubAssembler::DispatchByElementsKind(
TNode<Int32T> elements_kind, const ElementsKindSwitchCase& case_function) {
Label next(this), if_unknown_type(this, Label::kDeferred);
int32_t elements_kinds[] = {
#define ELEMENTS_KINDS_CASE(KIND) KIND,
ELEMENTS_KINDS(ELEMENTS_KINDS_CASE)
#undef ELEMENTS_KINDS_CASE
};
#define ELEMENTS_KINDS_CASE(KIND) Label if_##KIND(this);
ELEMENTS_KINDS(ELEMENTS_KINDS_CASE)
#undef ELEMENTS_KINDS_CASE
Label* elements_kind_labels[] = {
#define ELEMENTS_KINDS_CASE(KIND) &if_##KIND,
ELEMENTS_KINDS(ELEMENTS_KINDS_CASE)
#undef ELEMENTS_KINDS_CASE
};
STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels));
Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
arraysize(elements_kinds));
#define ELEMENTS_KINDS_CASE(KIND) \
BIND(&if_##KIND); \
{ \
case_function(KIND); \
Goto(&next); \
}
ELEMENTS_KINDS(ELEMENTS_KINDS_CASE)
#undef ELEMENTS_KINDS_CASE
BIND(&if_unknown_type);
Unreachable();
BIND(&next);
}
#undef ELEMENTS_KINDS
} // namespace
TF_STUB(StoreFastElementStub, HandlerStubAssembler) {
Comment("StoreFastElementStub: store_mode=%d", stub->store_mode());
Node* receiver = Parameter(Descriptor::kReceiver);
Node* key = Parameter(Descriptor::kName);
......@@ -320,30 +473,24 @@ TF_STUB(StoreFastElementStub, CodeStubAssembler) {
Label miss(this);
EmitElementStore(receiver, key, value, stub->elements_kind(),
stub->store_mode(), &miss, context);
// TODO(v8:8481): Pass elements_kind in feedback vector slots.
DispatchByElementsKind(LoadElementsKind(receiver),
[=, &miss](ElementsKind elements_kind) {
EmitElementStore(receiver, key, value, elements_kind,
stub->store_mode(), &miss, context);
});
Return(value);
BIND(&miss);
{
Comment("Miss");
TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
receiver, key);
}
TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
receiver, key);
}
// static
void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
StoreFastElementStub(isolate, HOLEY_ELEMENTS, STANDARD_STORE).GetCode();
StoreFastElementStub(isolate, HOLEY_ELEMENTS,
STORE_AND_GROW_NO_TRANSITION_HANDLE_COW)
StoreFastElementStub(isolate, STANDARD_STORE).GetCode();
StoreFastElementStub(isolate, STORE_AND_GROW_NO_TRANSITION_HANDLE_COW)
.GetCode();
for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
ElementsKind kind = static_cast<ElementsKind>(i);
StoreFastElementStub(isolate, kind, STANDARD_STORE).GetCode();
StoreFastElementStub(isolate, kind, STORE_AND_GROW_NO_TRANSITION_HANDLE_COW)
.GetCode();
}
}
......
......@@ -503,52 +503,35 @@ class JSEntryStub : public PlatformCodeStub {
class StoreFastElementStub : public TurboFanCodeStub {
public:
StoreFastElementStub(Isolate* isolate, ElementsKind elements_kind,
KeyedAccessStoreMode mode)
StoreFastElementStub(Isolate* isolate, KeyedAccessStoreMode mode)
: TurboFanCodeStub(isolate) {
minor_key_ = CommonStoreModeBits::encode(mode) |
ElementsKindBits::encode(elements_kind);
minor_key_ = CommonStoreModeBits::encode(mode);
}
static void GenerateAheadOfTime(Isolate* isolate);
ElementsKind elements_kind() const {
return ElementsKindBits::decode(minor_key_);
}
KeyedAccessStoreMode store_mode() const {
return CommonStoreModeBits::decode(minor_key_);
}
private:
class ElementsKindBits
: public BitField<ElementsKind, CommonStoreModeBits::kNext, 8> {};
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector);
DEFINE_TURBOFAN_CODE_STUB(StoreFastElement, TurboFanCodeStub);
};
class ElementsTransitionAndStoreStub : public TurboFanCodeStub {
public:
ElementsTransitionAndStoreStub(Isolate* isolate, ElementsKind from_kind,
ElementsKind to_kind,
ElementsTransitionAndStoreStub(Isolate* isolate,
KeyedAccessStoreMode store_mode)
: TurboFanCodeStub(isolate) {
minor_key_ = CommonStoreModeBits::encode(store_mode) |
FromBits::encode(from_kind) | ToBits::encode(to_kind);
minor_key_ = CommonStoreModeBits::encode(store_mode);
}
ElementsKind from_kind() const { return FromBits::decode(minor_key_); }
ElementsKind to_kind() const { return ToBits::decode(minor_key_); }
KeyedAccessStoreMode store_mode() const {
return CommonStoreModeBits::decode(minor_key_);
}
private:
class FromBits
: public BitField<ElementsKind, CommonStoreModeBits::kNext, 8> {};
class ToBits : public BitField<ElementsKind, 11, 8> {};
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreTransition);
DEFINE_TURBOFAN_CODE_STUB(ElementsTransitionAndStore, TurboFanCodeStub);
};
......
......@@ -71,12 +71,12 @@ enum ElementsKind : uint8_t {
TERMINAL_FAST_ELEMENTS_KIND = HOLEY_ELEMENTS
};
const int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
const int kFastElementsKindCount =
constexpr int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
constexpr int kFastElementsKindCount =
LAST_FAST_ELEMENTS_KIND - FIRST_FAST_ELEMENTS_KIND + 1;
// The number to add to a packed elements kind to reach a holey elements kind
const int kFastElementsKindPackedToHoley =
constexpr int kFastElementsKindPackedToHoley =
HOLEY_SMI_ELEMENTS - PACKED_SMI_ELEMENTS;
int ElementsKindToShiftSize(ElementsKind elements_kind);
......
......@@ -182,11 +182,8 @@ KeyedAccessLoadMode LoadHandler::GetKeyedAccessLoadMode(MaybeObject handler) {
Handle<Object> StoreHandler::StoreElementTransition(
Isolate* isolate, Handle<Map> receiver_map, Handle<Map> transition,
KeyedAccessStoreMode store_mode) {
ElementsKind elements_kind = receiver_map->elements_kind();
Handle<Code> stub =
ElementsTransitionAndStoreStub(isolate, elements_kind,
transition->elements_kind(), store_mode)
.GetCode();
ElementsTransitionAndStoreStub(isolate, store_mode).GetCode();
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(1);
......
......@@ -1843,7 +1843,6 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
}
// TODO(ishell): move to StoreHandler::StoreElement().
ElementsKind elements_kind = receiver_map->elements_kind();
Handle<Code> stub;
if (receiver_map->has_sloppy_arguments_elements()) {
// TODO(jgruber): Update counter name.
......@@ -1853,7 +1852,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
} else if (receiver_map->has_fast_elements() ||
receiver_map->has_fixed_typed_array_elements()) {
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
stub = StoreFastElementStub(isolate(), elements_kind, store_mode).GetCode();
stub = StoreFastElementStub(isolate(), store_mode).GetCode();
if (receiver_map->has_fixed_typed_array_elements()) return stub;
} else if (IsStoreInArrayLiteralICKind(kind())) {
// TODO(jgruber): Update counter name.
......@@ -1863,7 +1862,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
} else {
// TODO(jgruber): Update counter name.
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind);
DCHECK_EQ(DICTIONARY_ELEMENTS, receiver_map->elements_kind());
stub = CodeFactory::KeyedStoreIC_Slow(isolate(), store_mode).code();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment