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, ...@@ -10387,9 +10387,14 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
// Skip the store if we write beyond the length or // Skip the store if we write beyond the length or
// to a property with a negative integer index. // to a property with a negative integer index.
GotoIfNot(UintPtrLessThan(intptr_key, length), &done); GotoIfNot(UintPtrLessThan(intptr_key, length), &done);
} else { } else if (store_mode == STANDARD_STORE) {
DCHECK_EQ(STANDARD_STORE, store_mode);
GotoIfNot(UintPtrLessThan(intptr_key, length), bailout); 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 || if (elements_kind == BIGINT64_ELEMENTS ||
...@@ -10412,8 +10417,7 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, ...@@ -10412,8 +10417,7 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
BIND(&done); BIND(&done);
return; return;
} }
DCHECK(IsSmiOrObjectElementsKind(elements_kind) || DCHECK(IsFastElementsKind(elements_kind));
IsDoubleElementsKind(elements_kind));
Node* length = Node* length =
SelectImpl(IsJSArray(object), [=]() { return LoadJSArrayLength(object); }, SelectImpl(IsJSArray(object), [=]() { return LoadJSArrayLength(object); },
......
...@@ -266,7 +266,97 @@ Handle<Code> TurboFanCodeStub::GenerateCode() { ...@@ -266,7 +266,97 @@ Handle<Code> TurboFanCodeStub::GenerateCode() {
&state, AssemblerOptions::Default(isolate())); &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* receiver = Parameter(Descriptor::kReceiver);
Node* key = Parameter(Descriptor::kName); Node* key = Parameter(Descriptor::kName);
Node* value = Parameter(Descriptor::kValue); Node* value = Parameter(Descriptor::kValue);
...@@ -275,10 +365,7 @@ TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) { ...@@ -275,10 +365,7 @@ TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) {
Node* vector = Parameter(Descriptor::kVector); Node* vector = Parameter(Descriptor::kVector);
Node* context = Parameter(Descriptor::kContext); Node* context = Parameter(Descriptor::kContext);
Comment( Comment("ElementsTransitionAndStoreStub: store_mode=%d", stub->store_mode());
"ElementsTransitionAndStoreStub: from_kind=%s, to_kind=%s, store_mode=%d",
ElementsKindToString(stub->from_kind()),
ElementsKindToString(stub->to_kind()), stub->store_mode());
Label miss(this); Label miss(this);
...@@ -286,19 +373,20 @@ TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) { ...@@ -286,19 +373,20 @@ TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) {
// Tracing elements transitions is the job of the runtime. // Tracing elements transitions is the job of the runtime.
Goto(&miss); Goto(&miss);
} else { } else {
TransitionElementsKind(receiver, map, stub->from_kind(), stub->to_kind(), // TODO(v8:8481): Pass from_kind and to_kind in feedback vector slots.
&miss); DispatchForElementsKindTransition(
EmitElementStore(receiver, key, value, stub->to_kind(), stub->store_mode(), LoadElementsKind(receiver), LoadMapElementsKind(map),
&miss, context); [=, &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); Return(value);
} }
BIND(&miss); BIND(&miss);
{ TailCallRuntime(Runtime::kElementsTransitionAndStoreIC_Miss, context,
Comment("Miss"); receiver, key, value, map, slot, vector);
TailCallRuntime(Runtime::kElementsTransitionAndStoreIC_Miss, context,
receiver, key, value, map, slot, vector);
}
} }
int JSEntryStub::GenerateHandlerTable(MacroAssembler* masm) { int JSEntryStub::GenerateHandlerTable(MacroAssembler* masm) {
...@@ -307,9 +395,74 @@ int JSEntryStub::GenerateHandlerTable(MacroAssembler* masm) { ...@@ -307,9 +395,74 @@ int JSEntryStub::GenerateHandlerTable(MacroAssembler* masm) {
return handler_table_offset; return handler_table_offset;
} }
TF_STUB(StoreFastElementStub, CodeStubAssembler) { namespace {
Comment("StoreFastElementStub: elements_kind=%s, store_mode=%d",
ElementsKindToString(stub->elements_kind()), stub->store_mode()); // 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* receiver = Parameter(Descriptor::kReceiver);
Node* key = Parameter(Descriptor::kName); Node* key = Parameter(Descriptor::kName);
...@@ -320,30 +473,24 @@ TF_STUB(StoreFastElementStub, CodeStubAssembler) { ...@@ -320,30 +473,24 @@ TF_STUB(StoreFastElementStub, CodeStubAssembler) {
Label miss(this); Label miss(this);
EmitElementStore(receiver, key, value, stub->elements_kind(), // TODO(v8:8481): Pass elements_kind in feedback vector slots.
stub->store_mode(), &miss, context); DispatchByElementsKind(LoadElementsKind(receiver),
[=, &miss](ElementsKind elements_kind) {
EmitElementStore(receiver, key, value, elements_kind,
stub->store_mode(), &miss, context);
});
Return(value); Return(value);
BIND(&miss); BIND(&miss);
{ TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
Comment("Miss"); receiver, key);
TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
receiver, key);
}
} }
// static // static
void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) { void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
StoreFastElementStub(isolate, HOLEY_ELEMENTS, STANDARD_STORE).GetCode(); StoreFastElementStub(isolate, STANDARD_STORE).GetCode();
StoreFastElementStub(isolate, HOLEY_ELEMENTS, StoreFastElementStub(isolate, STORE_AND_GROW_NO_TRANSITION_HANDLE_COW)
STORE_AND_GROW_NO_TRANSITION_HANDLE_COW)
.GetCode(); .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 { ...@@ -503,52 +503,35 @@ class JSEntryStub : public PlatformCodeStub {
class StoreFastElementStub : public TurboFanCodeStub { class StoreFastElementStub : public TurboFanCodeStub {
public: public:
StoreFastElementStub(Isolate* isolate, ElementsKind elements_kind, StoreFastElementStub(Isolate* isolate, KeyedAccessStoreMode mode)
KeyedAccessStoreMode mode)
: TurboFanCodeStub(isolate) { : TurboFanCodeStub(isolate) {
minor_key_ = CommonStoreModeBits::encode(mode) | minor_key_ = CommonStoreModeBits::encode(mode);
ElementsKindBits::encode(elements_kind);
} }
static void GenerateAheadOfTime(Isolate* isolate); static void GenerateAheadOfTime(Isolate* isolate);
ElementsKind elements_kind() const {
return ElementsKindBits::decode(minor_key_);
}
KeyedAccessStoreMode store_mode() const { KeyedAccessStoreMode store_mode() const {
return CommonStoreModeBits::decode(minor_key_); return CommonStoreModeBits::decode(minor_key_);
} }
private: private:
class ElementsKindBits
: public BitField<ElementsKind, CommonStoreModeBits::kNext, 8> {};
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector); DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector);
DEFINE_TURBOFAN_CODE_STUB(StoreFastElement, TurboFanCodeStub); DEFINE_TURBOFAN_CODE_STUB(StoreFastElement, TurboFanCodeStub);
}; };
class ElementsTransitionAndStoreStub : public TurboFanCodeStub { class ElementsTransitionAndStoreStub : public TurboFanCodeStub {
public: public:
ElementsTransitionAndStoreStub(Isolate* isolate, ElementsKind from_kind, ElementsTransitionAndStoreStub(Isolate* isolate,
ElementsKind to_kind,
KeyedAccessStoreMode store_mode) KeyedAccessStoreMode store_mode)
: TurboFanCodeStub(isolate) { : TurboFanCodeStub(isolate) {
minor_key_ = CommonStoreModeBits::encode(store_mode) | minor_key_ = CommonStoreModeBits::encode(store_mode);
FromBits::encode(from_kind) | ToBits::encode(to_kind);
} }
ElementsKind from_kind() const { return FromBits::decode(minor_key_); }
ElementsKind to_kind() const { return ToBits::decode(minor_key_); }
KeyedAccessStoreMode store_mode() const { KeyedAccessStoreMode store_mode() const {
return CommonStoreModeBits::decode(minor_key_); return CommonStoreModeBits::decode(minor_key_);
} }
private: private:
class FromBits
: public BitField<ElementsKind, CommonStoreModeBits::kNext, 8> {};
class ToBits : public BitField<ElementsKind, 11, 8> {};
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreTransition); DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreTransition);
DEFINE_TURBOFAN_CODE_STUB(ElementsTransitionAndStore, TurboFanCodeStub); DEFINE_TURBOFAN_CODE_STUB(ElementsTransitionAndStore, TurboFanCodeStub);
}; };
......
...@@ -71,12 +71,12 @@ enum ElementsKind : uint8_t { ...@@ -71,12 +71,12 @@ enum ElementsKind : uint8_t {
TERMINAL_FAST_ELEMENTS_KIND = HOLEY_ELEMENTS TERMINAL_FAST_ELEMENTS_KIND = HOLEY_ELEMENTS
}; };
const int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1; constexpr int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
const int kFastElementsKindCount = constexpr int kFastElementsKindCount =
LAST_FAST_ELEMENTS_KIND - FIRST_FAST_ELEMENTS_KIND + 1; LAST_FAST_ELEMENTS_KIND - FIRST_FAST_ELEMENTS_KIND + 1;
// The number to add to a packed elements kind to reach a holey elements kind // 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; HOLEY_SMI_ELEMENTS - PACKED_SMI_ELEMENTS;
int ElementsKindToShiftSize(ElementsKind elements_kind); int ElementsKindToShiftSize(ElementsKind elements_kind);
......
...@@ -182,11 +182,8 @@ KeyedAccessLoadMode LoadHandler::GetKeyedAccessLoadMode(MaybeObject handler) { ...@@ -182,11 +182,8 @@ KeyedAccessLoadMode LoadHandler::GetKeyedAccessLoadMode(MaybeObject handler) {
Handle<Object> StoreHandler::StoreElementTransition( Handle<Object> StoreHandler::StoreElementTransition(
Isolate* isolate, Handle<Map> receiver_map, Handle<Map> transition, Isolate* isolate, Handle<Map> receiver_map, Handle<Map> transition,
KeyedAccessStoreMode store_mode) { KeyedAccessStoreMode store_mode) {
ElementsKind elements_kind = receiver_map->elements_kind();
Handle<Code> stub = Handle<Code> stub =
ElementsTransitionAndStoreStub(isolate, elements_kind, ElementsTransitionAndStoreStub(isolate, store_mode).GetCode();
transition->elements_kind(), store_mode)
.GetCode();
Handle<Object> validity_cell = Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate); Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(1); Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(1);
......
...@@ -1843,7 +1843,6 @@ Handle<Object> KeyedStoreIC::StoreElementHandler( ...@@ -1843,7 +1843,6 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
} }
// TODO(ishell): move to StoreHandler::StoreElement(). // TODO(ishell): move to StoreHandler::StoreElement().
ElementsKind elements_kind = receiver_map->elements_kind();
Handle<Code> stub; Handle<Code> stub;
if (receiver_map->has_sloppy_arguments_elements()) { if (receiver_map->has_sloppy_arguments_elements()) {
// TODO(jgruber): Update counter name. // TODO(jgruber): Update counter name.
...@@ -1853,7 +1852,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler( ...@@ -1853,7 +1852,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
} else if (receiver_map->has_fast_elements() || } else if (receiver_map->has_fast_elements() ||
receiver_map->has_fixed_typed_array_elements()) { receiver_map->has_fixed_typed_array_elements()) {
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub); 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; if (receiver_map->has_fixed_typed_array_elements()) return stub;
} else if (IsStoreInArrayLiteralICKind(kind())) { } else if (IsStoreInArrayLiteralICKind(kind())) {
// TODO(jgruber): Update counter name. // TODO(jgruber): Update counter name.
...@@ -1863,7 +1862,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler( ...@@ -1863,7 +1862,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
} else { } else {
// TODO(jgruber): Update counter name. // TODO(jgruber): Update counter name.
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub); 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(); 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