Commit 8bc54052 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[csa] Merge in- and out-of-object store paths

Rather than duplicating code paths for in- and out-of-object stores,
have one code path which checks whether it needs to load the property
store (and change the storage location to the HeapNumber value for
unboxed doubles).

As a drive-by, change the representation dispatch into a switch, and
inline the representation checks into that switch, to make explicit
what checks for what and which paths transform the value. Also, TNodify
some of the surrounding functions.

Change-Id: Ia1bf698b4cec3ffce9aaa5732cda2e3be9efd8e8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1795345Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63652}
parent d7d25d2a
......@@ -5609,45 +5609,22 @@ void CodeStubAssembler::InitializeAllocationMemento(Node* base,
Comment("]");
}
Node* CodeStubAssembler::TryTaggedToFloat64(Node* value,
Label* if_valueisnotnumber) {
Label out(this);
VARIABLE(var_result, MachineRepresentation::kFloat64);
// Check if the {value} is a Smi or a HeapObject.
Label if_valueissmi(this), if_valueisnotsmi(this);
Branch(TaggedIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
BIND(&if_valueissmi);
{
// Convert the Smi {value}.
var_result.Bind(SmiToFloat64(value));
Goto(&out);
}
BIND(&if_valueisnotsmi);
{
// Check if {value} is a HeapNumber.
Label if_valueisheapnumber(this);
Branch(IsHeapNumber(value), &if_valueisheapnumber, if_valueisnotnumber);
BIND(&if_valueisheapnumber);
{
// Load the floating point value.
var_result.Bind(LoadHeapNumberValue(value));
Goto(&out);
}
}
BIND(&out);
return var_result.value();
TNode<Float64T> CodeStubAssembler::TryTaggedToFloat64(
TNode<Object> value, Label* if_valueisnotnumber) {
return Select<Float64T>(
TaggedIsSmi(value), [&]() { return SmiToFloat64(CAST(value)); },
[&]() {
GotoIfNot(IsHeapNumber(CAST(value)), if_valueisnotnumber);
return LoadHeapNumberValue(CAST(value));
});
}
Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) {
TNode<Float64T> CodeStubAssembler::TruncateTaggedToFloat64(
SloppyTNode<Context> context, SloppyTNode<Object> value) {
// We might need to loop once due to ToNumber conversion.
VARIABLE(var_value, MachineRepresentation::kTagged);
VARIABLE(var_result, MachineRepresentation::kFloat64);
TVARIABLE(Object, var_value, value);
TVARIABLE(Float64T, var_result);
Label loop(this, &var_value), done_loop(this, &var_result);
var_value.Bind(value);
Goto(&loop);
BIND(&loop);
{
......@@ -5658,14 +5635,13 @@ Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) {
// Convert {value} to Float64 if it is a number and convert it to a number
// otherwise.
Node* const result = TryTaggedToFloat64(value, &if_valueisnotnumber);
var_result.Bind(result);
var_result = TryTaggedToFloat64(value, &if_valueisnotnumber);
Goto(&done_loop);
BIND(&if_valueisnotnumber);
{
// Convert the {value} to a Number first.
var_value.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, value));
var_value = CallBuiltin(Builtins::kNonNumberToNumber, context, value);
Goto(&loop);
}
}
......@@ -5673,13 +5649,14 @@ Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) {
return var_result.value();
}
Node* CodeStubAssembler::TruncateTaggedToWord32(Node* context, Node* value) {
TNode<Word32T> CodeStubAssembler::TruncateTaggedToWord32(
SloppyTNode<Context> context, SloppyTNode<Object> value) {
VARIABLE(var_result, MachineRepresentation::kWord32);
Label done(this);
TaggedToWord32OrBigIntImpl<Object::Conversion::kToNumber>(context, value,
&done, &var_result);
BIND(&done);
return var_result.value();
return UncheckedCast<Word32T>(var_result.value());
}
// Truncate {value} to word32 and jump to {if_number} if it is a Number,
......@@ -10945,7 +10922,7 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
if (IsSmiElementsKind(elements_kind)) {
GotoIfNot(TaggedIsSmi(value), bailout);
} else if (IsDoubleElementsKind(elements_kind)) {
value = TryTaggedToFloat64(value, bailout);
value = TryTaggedToFloat64(CAST(value), bailout);
}
if (IsGrowStoreMode(store_mode) &&
......
......@@ -2242,9 +2242,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
Node* base_allocation_size,
Node* allocation_site);
Node* TryTaggedToFloat64(Node* value, Label* if_valueisnotnumber);
Node* TruncateTaggedToFloat64(Node* context, Node* value);
Node* TruncateTaggedToWord32(Node* context, Node* value);
TNode<Float64T> TryTaggedToFloat64(TNode<Object> value,
Label* if_valueisnotnumber);
TNode<Float64T> TruncateTaggedToFloat64(SloppyTNode<Context> context,
SloppyTNode<Object> value);
TNode<Word32T> TruncateTaggedToWord32(SloppyTNode<Context> context,
SloppyTNode<Object> value);
void TaggedToWord32OrBigInt(Node* context, Node* value, Label* if_number,
Variable* var_word32, Label* if_bigint,
Variable* var_bigint);
......
......@@ -5,6 +5,7 @@
#include "src/ic/accessor-assembler.h"
#include "src/ast/ast.h"
#include "src/base/optional.h"
#include "src/codegen/code-factory.h"
#include "src/ic/handler-configuration.h"
#include "src/ic/ic.h"
......@@ -924,10 +925,10 @@ void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable,
}
void AccessorAssembler::HandleStoreICNativeDataProperty(
const StoreICParameters* p, Node* holder, Node* handler_word) {
const StoreICParameters* p, Node* holder, TNode<Word32T> handler_word) {
Comment("native_data_property_store");
TNode<IntPtrT> descriptor =
Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
TNode<AccessorInfo> accessor_info =
CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
......@@ -949,7 +950,7 @@ void AccessorAssembler::HandleStoreICHandlerCase(
BIND(&if_smi_handler);
{
Node* holder = p->receiver();
TNode<IntPtrT> handler_word = SmiUntag(CAST(handler));
TNode<Int32T> handler_word = SmiToInt32(CAST(handler));
Label if_fast_smi(this), if_proxy(this), if_interceptor(this),
if_slow(this);
......@@ -960,19 +961,19 @@ void AccessorAssembler::HandleStoreICHandlerCase(
STATIC_ASSERT(StoreHandler::kSlow + 1 == StoreHandler::kProxy);
STATIC_ASSERT(StoreHandler::kProxy + 1 == StoreHandler::kKindsNumber);
TNode<UintPtrT> handler_kind =
DecodeWord<StoreHandler::KindBits>(handler_word);
GotoIf(IntPtrLessThan(handler_kind,
IntPtrConstant(StoreHandler::kGlobalProxy)),
TNode<Uint32T> handler_kind =
DecodeWord32<StoreHandler::KindBits>(handler_word);
GotoIf(
Int32LessThan(handler_kind, Int32Constant(StoreHandler::kGlobalProxy)),
&if_fast_smi);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)),
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kProxy)),
&if_proxy);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kInterceptor)),
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kInterceptor)),
&if_interceptor);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kSlow)),
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kSlow)),
&if_slow);
CSA_ASSERT(this,
WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)));
Word32Equal(handler_kind, Int32Constant(StoreHandler::kNormal)));
TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder));
TVARIABLE(IntPtrT, var_name_index);
......@@ -996,14 +997,14 @@ void AccessorAssembler::HandleStoreICHandlerCase(
BIND(&if_fast_smi);
{
TNode<UintPtrT> handler_kind =
DecodeWord<StoreHandler::KindBits>(handler_word);
TNode<Uint32T> handler_kind =
DecodeWord32<StoreHandler::KindBits>(handler_word);
Label data(this), accessor(this), native_data_property(this);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)),
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kAccessor)),
&accessor);
Branch(WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kNativeDataProperty)),
Branch(Word32Equal(handler_kind,
Int32Constant(StoreHandler::kNativeDataProperty)),
&native_data_property, &data);
BIND(&accessor);
......@@ -1408,10 +1409,11 @@ void AccessorAssembler::CheckPrototypeValidityCell(
}
void AccessorAssembler::HandleStoreAccessor(const StoreICParameters* p,
Node* holder, Node* handler_word) {
Node* holder,
TNode<Word32T> handler_word) {
Comment("accessor_store");
TNode<IntPtrT> descriptor =
Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
TNode<HeapObject> accessor_pair =
CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
CSA_ASSERT(this, IsAccessorPair(accessor_pair));
......@@ -1484,42 +1486,43 @@ void AccessorAssembler::HandleStoreICProtoHandler(
if_interceptor(this);
CSA_ASSERT(this, TaggedIsSmi(smi_handler));
TNode<IntPtrT> handler_word = SmiUntag(smi_handler);
TNode<Int32T> handler_word = SmiToInt32(smi_handler);
TNode<UintPtrT> handler_kind =
DecodeWord<StoreHandler::KindBits>(handler_word);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)),
TNode<Uint32T> handler_kind =
DecodeWord32<StoreHandler::KindBits>(handler_word);
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kNormal)),
&if_add_normal);
TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
CSA_ASSERT(this, IsWeakOrCleared(maybe_holder));
TNode<HeapObject> holder = GetHeapObjectAssumeWeak(maybe_holder, miss);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kGlobalProxy)),
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kGlobalProxy)),
&if_store_global_proxy);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)),
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kAccessor)),
&if_accessor);
GotoIf(WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kNativeDataProperty)),
GotoIf(Word32Equal(handler_kind,
Int32Constant(StoreHandler::kNativeDataProperty)),
&if_native_data_property);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kApiSetter)),
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kApiSetter)),
&if_api_setter);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kSlow)),
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kSlow)),
&if_slow);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kInterceptor)),
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kInterceptor)),
&if_interceptor);
GotoIf(WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kApiSetterHolderIsPrototype)),
GotoIf(
Word32Equal(handler_kind,
Int32Constant(StoreHandler::kApiSetterHolderIsPrototype)),
&if_api_setter);
CSA_ASSERT(this,
WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)));
Word32Equal(handler_kind, Int32Constant(StoreHandler::kProxy)));
HandleStoreToProxy(p, holder, miss, support_elements);
BIND(&if_slow);
......@@ -1575,7 +1578,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
// Context is stored either in data2 or data3 field depending on whether
// the access check is enabled for this handler or not.
TNode<MaybeObject> maybe_context = Select<MaybeObject>(
IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word),
IsSetWord32<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word),
[=] { return LoadHandlerDataField(handler, 3); },
[=] { return LoadHandlerDataField(handler, 2); });
......@@ -1593,13 +1596,13 @@ void AccessorAssembler::HandleStoreICProtoHandler(
VARIABLE(api_holder, MachineRepresentation::kTagged, p->receiver());
Label store(this);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kApiSetter)),
GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kApiSetter)),
&store);
CSA_ASSERT(
this,
WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kApiSetterHolderIsPrototype)));
CSA_ASSERT(this,
Word32Equal(
handler_kind,
Int32Constant(StoreHandler::kApiSetterHolderIsPrototype)));
api_holder.Bind(LoadMapPrototype(LoadMap(p->receiver())));
Goto(&store);
......@@ -1654,127 +1657,87 @@ void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
}
}
void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
Node* holder, Node* value,
Label* miss) {
void AccessorAssembler::HandleStoreICSmiHandlerCase(
SloppyTNode<Word32T> handler_word, SloppyTNode<JSObject> holder,
SloppyTNode<Object> value, Label* miss) {
Comment("field store");
#ifdef DEBUG
TNode<UintPtrT> handler_kind =
DecodeWord<StoreHandler::KindBits>(handler_word);
TNode<Uint32T> handler_kind =
DecodeWord32<StoreHandler::KindBits>(handler_word);
CSA_ASSERT(
this,
Word32Or(
WordEqual(handler_kind, IntPtrConstant(StoreHandler::kField)),
WordEqual(handler_kind, IntPtrConstant(StoreHandler::kConstField))));
Word32Equal(handler_kind, Int32Constant(StoreHandler::kField)),
Word32Equal(handler_kind, Int32Constant(StoreHandler::kConstField))));
#endif
TNode<UintPtrT> field_representation =
DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word);
TNode<Uint32T> field_representation =
DecodeWord32<StoreHandler::RepresentationBits>(handler_word);
Label if_smi_field(this), if_double_field(this), if_heap_object_field(this),
if_tagged_field(this);
GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)),
&if_tagged_field);
GotoIf(WordEqual(field_representation,
IntPtrConstant(StoreHandler::kHeapObject)),
&if_heap_object_field);
GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)),
&if_double_field);
CSA_ASSERT(this, WordEqual(field_representation,
IntPtrConstant(StoreHandler::kSmi)));
Goto(&if_smi_field);
int32_t case_values[] = {Representation::kTagged, Representation::kHeapObject,
Representation::kSmi};
Label* case_labels[] = {&if_tagged_field, &if_heap_object_field,
&if_smi_field};
Switch(field_representation, &if_double_field, case_values, case_labels, 3);
BIND(&if_tagged_field);
{
Comment("store tagged field");
HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(),
value, miss);
}
BIND(&if_double_field);
{
Comment("store double field");
HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(),
value, miss);
HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt,
Representation::Tagged(), miss);
}
BIND(&if_heap_object_field);
{
Comment("heap object field checks");
CheckHeapObjectTypeMatchesDescriptor(handler_word, holder, value, miss);
Comment("store heap object field");
HandleStoreFieldAndReturn(handler_word, holder,
Representation::HeapObject(), value, miss);
HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt,
Representation::HeapObject(), miss);
}
BIND(&if_smi_field);
{
Comment("smi field checks");
GotoIfNot(TaggedIsSmi(value), miss);
Comment("store smi field");
HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(),
value, miss);
HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt,
Representation::Smi(), miss);
}
}
void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
Node* holder,
Representation representation,
Node* value, Label* miss) {
Node* prepared_value =
PrepareValueForStore(handler_word, holder, representation, value, miss);
Label if_inobject(this), if_out_of_object(this);
Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject,
&if_out_of_object);
BIND(&if_inobject);
BIND(&if_double_field);
{
StoreNamedField(handler_word, holder, true, representation, prepared_value,
miss);
Return(value);
}
CSA_ASSERT(this, Word32Equal(field_representation,
Int32Constant(Representation::kDouble)));
Comment("double field checks");
TNode<Float64T> double_value = TryTaggedToFloat64(value, miss);
CheckDescriptorConsidersNumbersMutable(handler_word, holder, miss);
BIND(&if_out_of_object);
{
StoreNamedField(handler_word, holder, false, representation, prepared_value,
miss);
Return(value);
Comment("store double field");
HandleStoreFieldAndReturn(handler_word, holder, value, double_value,
Representation::Double(), miss);
}
}
Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
Representation representation,
Node* value, Label* bailout) {
if (representation.IsDouble()) {
value = TryTaggedToFloat64(value, bailout);
// We have to check that the representation is still Double. Checking the
// value is nor enough, as we could have transitioned to Tagged but still
// be holding a HeapNumber, which would no longer be allowed to be mutable.
// TODO(leszeks): We could skip the representation check in favor of a
// constant value check in StoreNamedField here, but then StoreNamedField
// would need an IsHeapNumber check in case both the representation changed
// and the value is no longer a HeapNumber.
TNode<IntPtrT> descriptor_entry =
Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
TNode<DescriptorArray> descriptors = LoadMapDescriptors(LoadMap(holder));
TNode<Uint32T> details =
LoadDetailsByDescriptorEntry(descriptors, descriptor_entry);
GotoIfNot(IsEqualInWord32<PropertyDetails::RepresentationField>(
details, Representation::kDouble),
bailout);
} else if (representation.IsHeapObject()) {
void AccessorAssembler::CheckHeapObjectTypeMatchesDescriptor(
TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value,
Label* bailout) {
GotoIf(TaggedIsSmi(value), bailout);
Label done(this);
// Skip field type check in favor of constant value check when storing
// to constant field.
GotoIf(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
IntPtrConstant(StoreHandler::kConstField)),
GotoIf(Word32Equal(DecodeWord32<StoreHandler::KindBits>(handler_word),
Int32Constant(StoreHandler::kConstField)),
&done);
TNode<IntPtrT> descriptor =
Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
TNode<MaybeObject> maybe_field_type =
LoadDescriptorValueOrFieldType(LoadMap(holder), descriptor);
......@@ -1786,14 +1749,108 @@ Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
Branch(TaggedEqual(LoadMap(CAST(value)), field_type), &done, bailout);
}
BIND(&done);
}
} else if (representation.IsSmi()) {
GotoIfNot(TaggedIsSmi(value), bailout);
void AccessorAssembler::CheckDescriptorConsidersNumbersMutable(
TNode<Word32T> handler_word, TNode<JSObject> holder, Label* bailout) {
// We have to check that the representation is Double. Checking the value
// (either in the field or being assigned) is not enough, as we could have
// transitioned to Tagged but still be holding a HeapNumber, which would no
// longer be allowed to be mutable.
// TODO(leszeks): We could skip the representation check in favor of a
// constant value check in HandleStoreFieldAndReturn here, but then
// HandleStoreFieldAndReturn would need an IsHeapNumber check in case both the
// representation changed and the value is no longer a HeapNumber.
TNode<IntPtrT> descriptor_entry =
Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
TNode<DescriptorArray> descriptors = LoadMapDescriptors(LoadMap(holder));
TNode<Uint32T> details =
LoadDetailsByDescriptorEntry(descriptors, descriptor_entry);
GotoIfNot(IsEqualInWord32<PropertyDetails::RepresentationField>(
details, Representation::kDouble),
bailout);
}
void AccessorAssembler::HandleStoreFieldAndReturn(
TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value,
base::Optional<TNode<Float64T>> double_value, Representation representation,
Label* miss) {
Label done(this);
bool store_value_as_double = representation.IsDouble();
TNode<BoolT> is_inobject =
IsSetWord32<StoreHandler::IsInobjectBits>(handler_word);
TNode<HeapObject> property_storage = Select<HeapObject>(
is_inobject, [&]() { return holder; },
[&]() { return LoadFastProperties(holder); });
TNode<UintPtrT> index =
DecodeWordFromWord32<StoreHandler::FieldIndexBits>(handler_word);
TNode<IntPtrT> offset = Signed(TimesTaggedSize(index));
// For Double fields, we want to mutate the current double-value
// field rather than changing it to point at a new HeapNumber.
if (store_value_as_double) {
TVARIABLE(HeapObject, actual_property_storage, property_storage);
TVARIABLE(IntPtrT, actual_offset, offset);
Label property_and_offset_ready(this);
// If we are unboxing double fields, and this is an in-object field, the
// property_storage and offset are already pointing to the double-valued
// field.
if (FLAG_unbox_double_fields) {
GotoIf(is_inobject, &property_and_offset_ready);
}
// Store the double value directly into the mutable HeapNumber.
TNode<Object> field = LoadObjectField(property_storage, offset);
CSA_ASSERT(this, IsHeapNumber(CAST(field)));
actual_property_storage = CAST(field);
actual_offset = IntPtrConstant(HeapNumber::kValueOffset);
Goto(&property_and_offset_ready);
BIND(&property_and_offset_ready);
property_storage = actual_property_storage.value();
offset = actual_offset.value();
}
// Do constant value check if necessary.
Label do_store(this);
GotoIfNot(Word32Equal(DecodeWord32<StoreHandler::KindBits>(handler_word),
Int32Constant(StoreHandler::kConstField)),
&do_store);
{
if (store_value_as_double) {
Label done(this);
TNode<Float64T> current_value =
LoadObjectField<Float64T>(property_storage, offset);
BranchIfSameNumberValue(current_value, *double_value, &done, miss);
BIND(&done);
Return(value);
} else {
TNode<Object> current_value = LoadObjectField(property_storage, offset);
GotoIfNot(TaggedEqual(current_value, value), miss);
Return(value);
}
}
BIND(&do_store);
// Do the store.
if (store_value_as_double) {
StoreObjectFieldNoWriteBarrier(property_storage, offset, *double_value,
MachineRepresentation::kFloat64);
} else if (representation.IsSmi()) {
TNode<Smi> value_smi = CAST(value);
StoreObjectFieldNoWriteBarrier(property_storage, offset, value_smi);
} else {
DCHECK(representation.IsTagged());
StoreObjectField(property_storage, offset, value);
}
return value;
Return(value);
}
Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
......@@ -1894,59 +1951,6 @@ Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
}
}
void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
bool is_inobject,
Representation representation,
Node* value, Label* bailout) {
bool store_value_as_double = representation.IsDouble();
Node* property_storage = object;
if (!is_inobject) {
property_storage = LoadFastProperties(object);
}
TNode<UintPtrT> index =
DecodeWord<StoreHandler::FieldIndexBits>(handler_word);
TNode<IntPtrT> offset = Signed(TimesTaggedSize(index));
if (representation.IsDouble()) {
if (!FLAG_unbox_double_fields || !is_inobject) {
// Load the mutable heap number.
property_storage = LoadObjectField(property_storage, offset);
// Store the double value into it.
offset = IntPtrConstant(HeapNumber::kValueOffset);
}
}
// Do constant value check if necessary.
Label const_checked(this);
GotoIfNot(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
IntPtrConstant(StoreHandler::kConstField)),
&const_checked);
{
if (store_value_as_double) {
TNode<Float64T> current_value =
LoadObjectField<Float64T>(CAST(property_storage), offset);
BranchIfSameNumberValue(current_value, UncheckedCast<Float64T>(value),
&const_checked, bailout);
} else {
TNode<Object> current_value = LoadObjectField(property_storage, offset);
Branch(TaggedEqual(current_value, UncheckedCast<Object>(value)),
&const_checked, bailout);
}
}
BIND(&const_checked);
// Do the store.
if (store_value_as_double) {
StoreObjectFieldNoWriteBarrier(property_storage, offset, value,
MachineRepresentation::kFloat64);
} else if (representation.IsSmi()) {
TNode<Smi> value_smi = CAST(value);
StoreObjectFieldNoWriteBarrier(property_storage, offset, value_smi);
} else {
StoreObjectField(property_storage, offset, value);
}
}
void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
Node* elements,
Node* intptr_index,
......
......@@ -5,6 +5,7 @@
#ifndef V8_IC_ACCESSOR_ASSEMBLER_H_
#define V8_IC_ACCESSOR_ASSEMBLER_H_
#include "src/base/optional.h"
#include "src/codegen/code-stub-assembler.h"
namespace v8 {
......@@ -314,22 +315,24 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<StoreHandler> handler, Label* miss,
ICMode ic_mode,
ElementSupport support_elements);
void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
Node* value, Label* miss);
void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
Representation representation, Node* value,
Label* miss);
void HandleStoreICSmiHandlerCase(SloppyTNode<Word32T> handler_word,
SloppyTNode<JSObject> holder,
SloppyTNode<Object> value, Label* miss);
void HandleStoreFieldAndReturn(TNode<Word32T> handler_word,
TNode<JSObject> holder, TNode<Object> value,
base::Optional<TNode<Float64T>> double_value,
Representation representation, Label* miss);
void CheckPrototypeValidityCell(TNode<Object> maybe_validity_cell,
Label* miss);
void HandleStoreICNativeDataProperty(const StoreICParameters* p, Node* holder,
Node* handler_word);
TNode<Word32T> handler_word);
void HandleStoreToProxy(const StoreICParameters* p, Node* proxy, Label* miss,
ElementSupport support_elements);
void HandleStoreAccessor(const StoreICParameters* p, Node* holder,
Node* handler_word);
TNode<Word32T> handler_word);
// KeyedLoadIC_Generic implementation.
......@@ -355,18 +358,20 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
const OnFoundOnReceiver& on_found_on_receiver,
Label* miss, ICMode ic_mode);
Node* PrepareValueForStore(Node* handler_word, Node* holder,
Representation representation, Node* value,
void CheckHeapObjectTypeMatchesDescriptor(TNode<Word32T> handler_word,
TNode<JSObject> holder,
TNode<Object> value,
Label* bailout);
// Double fields store double values in a mutable box, where stores are
// writes into this box rather than HeapNumber assignment.
void CheckDescriptorConsidersNumbersMutable(TNode<Word32T> handler_word,
TNode<JSObject> holder,
Label* bailout);
// Extends properties backing store by JSObject::kFieldsAdded elements,
// returns updated properties backing store.
Node* ExtendPropertiesBackingStore(Node* object, Node* index);
void StoreNamedField(Node* handler_word, Node* object, bool is_inobject,
Representation representation, Node* value,
Label* bailout);
void EmitFastElementsBoundsCheck(Node* object, Node* elements,
Node* intptr_index,
Node* is_jsarray_condition, Label* miss);
......
......@@ -145,29 +145,12 @@ Handle<Smi> StoreHandler::StoreProxy(Isolate* isolate) {
Handle<Smi> StoreHandler::StoreField(Isolate* isolate, Kind kind,
int descriptor, FieldIndex field_index,
Representation representation) {
FieldRepresentation field_rep;
switch (representation.kind()) {
case Representation::kSmi:
field_rep = kSmi;
break;
case Representation::kDouble:
field_rep = kDouble;
break;
case Representation::kHeapObject:
field_rep = kHeapObject;
break;
case Representation::kTagged:
field_rep = kTagged;
break;
default:
UNREACHABLE();
}
DCHECK(!representation.IsNone());
DCHECK(kind == kField || kind == kConstField);
int config = KindBits::encode(kind) |
IsInobjectBits::encode(field_index.is_inobject()) |
FieldRepresentationBits::encode(field_rep) |
RepresentationBits::encode(representation.kind()) |
DescriptorBits::encode(descriptor) |
FieldIndexBits::encode(field_index.index());
return handle(Smi::FromInt(config), isolate);
......
......@@ -204,8 +204,6 @@ class StoreHandler final : public DataHandler {
};
using KindBits = BitField<Kind, 0, 4>;
enum FieldRepresentation { kSmi, kDouble, kHeapObject, kTagged };
// Applicable to kGlobalProxy, kProxy kinds.
// Defines whether access rights check should be done on receiver object.
......@@ -233,10 +231,10 @@ class StoreHandler final : public DataHandler {
// Encoding when KindBits contains kField or kTransitionToField.
//
using IsInobjectBits = DescriptorBits::Next<bool, 1>;
using FieldRepresentationBits = IsInobjectBits::Next<FieldRepresentation, 2>;
using RepresentationBits = IsInobjectBits::Next<Representation::Kind, 3>;
// +1 here is to cover all possible JSObject header sizes.
using FieldIndexBits =
FieldRepresentationBits::Next<unsigned, kDescriptorIndexBitCount + 1>;
RepresentationBits::Next<unsigned, kDescriptorIndexBitCount + 1>;
// Make sure we don't overflow the smi.
STATIC_ASSERT(FieldIndexBits::kLastUsedBit < kSmiValueSize);
......
......@@ -94,7 +94,7 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
void StoreElementWithCapacity(Node* receiver, TNode<Map> receiver_map,
SloppyTNode<FixedArrayBase> elements,
TNode<Word32T> elements_kind,
TNode<IntPtrT> index, Node* value,
TNode<IntPtrT> index, SloppyTNode<Object> value,
Node* context, Label* slow,
UpdateLength update_length);
......@@ -306,7 +306,7 @@ void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn(
void KeyedStoreGenericAssembler::StoreElementWithCapacity(
Node* receiver, TNode<Map> receiver_map,
SloppyTNode<FixedArrayBase> elements, TNode<Word32T> elements_kind,
TNode<IntPtrT> index, Node* value, Node* context, Label* slow,
TNode<IntPtrT> index, SloppyTNode<Object> value, Node* context, Label* slow,
UpdateLength update_length) {
if (update_length != kDontChangeLength) {
CSA_ASSERT(this, InstanceTypeEqual(LoadMapInstanceType(receiver_map),
......@@ -388,7 +388,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
{
Label transition_to_double(this), transition_to_object(this);
TNode<Context> native_context = LoadNativeContext(context);
Branch(TaggedEqual(LoadMap(value), HeapNumberMapConstant()),
Branch(TaggedEqual(LoadMap(CAST(value)), HeapNumberMapConstant()),
&transition_to_double, &transition_to_object);
BIND(&transition_to_double);
{
......@@ -405,7 +405,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
index, PACKED_DOUBLE_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
// Make sure we do not store signalling NaNs into double arrays.
TNode<Float64T> double_value =
Float64SilenceNaN(LoadHeapNumberValue(value));
Float64SilenceNaN(LoadHeapNumberValue(CAST(value)));
StoreNoWriteBarrier(MachineRepresentation::kFloat64, double_elements,
double_offset, double_value);
MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
......
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