[CSA] Avoid sign-extending LoadIC's Smi handler when possible

Smi handler in LoadIC is decoded to IntPtrT and result in
sign-extending Smi's value when pointer compression is enabled. This
CL avoid this sign-extension by decoding the Smi to Int32T.

Change-Id: I3ddd6dcec8654d6c13d472a077a55698359d126a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3740481
Commit-Queue: Hao A Xu <hao.a.xu@intel.com>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81525}
This commit is contained in:
Hao Xu 2022-07-06 00:35:27 +08:00 committed by V8 LUCI CQ
parent 5febb0622f
commit 8d9615edf6
2 changed files with 84 additions and 78 deletions

View File

@ -30,7 +30,7 @@ namespace internal {
//////////////////// Private helpers.
#define LOAD_KIND(kind) \
IntPtrConstant(static_cast<intptr_t>(LoadHandler::Kind::kind))
Int32Constant(static_cast<intptr_t>(LoadHandler::Kind::kind))
#define STORE_KIND(kind) \
Int32Constant(static_cast<intptr_t>(StoreHandler::Kind::kind))
@ -234,10 +234,10 @@ void AccessorAssembler::HandleLoadICHandlerCase(
void AccessorAssembler::HandleLoadCallbackProperty(
const LazyLoadICParameters* p, TNode<JSObject> holder,
TNode<WordT> handler_word, ExitPoint* exit_point) {
TNode<Word32T> handler_word, ExitPoint* exit_point) {
Comment("native_data_property_load");
TNode<IntPtrT> descriptor =
Signed(DecodeWord<LoadHandler::DescriptorBits>(handler_word));
Signed(DecodeWordFromWord32<LoadHandler::DescriptorBits>(handler_word));
Callable callable = CodeFactory::ApiGetter(isolate());
TNode<AccessorInfo> accessor_info =
@ -249,13 +249,13 @@ void AccessorAssembler::HandleLoadCallbackProperty(
void AccessorAssembler::HandleLoadAccessor(
const LazyLoadICParameters* p, TNode<CallHandlerInfo> call_handler_info,
TNode<WordT> handler_word, TNode<DataHandler> handler,
TNode<IntPtrT> handler_kind, ExitPoint* exit_point) {
TNode<Word32T> handler_word, TNode<DataHandler> handler,
TNode<Uint32T> handler_kind, ExitPoint* exit_point) {
Comment("api_getter");
// 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::DoAccessCheckOnLookupStartObjectBits>(
IsSetWord32<LoadHandler::DoAccessCheckOnLookupStartObjectBits>(
handler_word),
[=] { return LoadHandlerDataField(handler, 3); },
[=] { return LoadHandlerDataField(handler, 2); });
@ -270,10 +270,10 @@ void AccessorAssembler::HandleLoadAccessor(
TVARIABLE(HeapObject, api_holder, CAST(p->lookup_start_object()));
Label load(this);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kApiGetter)), &load);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kApiGetter)), &load);
CSA_DCHECK(this,
WordEqual(handler_kind, LOAD_KIND(kApiGetterHolderIsPrototype)));
Word32Equal(handler_kind, LOAD_KIND(kApiGetterHolderIsPrototype)));
api_holder = LoadMapPrototype(LoadMap(CAST(p->lookup_start_object())));
Goto(&load);
@ -285,23 +285,23 @@ void AccessorAssembler::HandleLoadAccessor(
}
void AccessorAssembler::HandleLoadField(TNode<JSObject> holder,
TNode<WordT> handler_word,
TNode<Word32T> handler_word,
TVariable<Float64T>* var_double_value,
Label* rebox_double, Label* miss,
ExitPoint* exit_point) {
Comment("LoadField");
TNode<IntPtrT> index =
Signed(DecodeWord<LoadHandler::FieldIndexBits>(handler_word));
Signed(DecodeWordFromWord32<LoadHandler::FieldIndexBits>(handler_word));
TNode<IntPtrT> offset = IntPtrMul(index, IntPtrConstant(kTaggedSize));
Label inobject(this), out_of_object(this);
Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject,
Branch(IsSetWord32<LoadHandler::IsInobjectBits>(handler_word), &inobject,
&out_of_object);
BIND(&inobject);
{
Label is_double(this);
GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
GotoIf(IsSetWord32<LoadHandler::IsDoubleBits>(handler_word), &is_double);
exit_point->Return(LoadObjectField(holder, offset));
BIND(&is_double);
@ -320,7 +320,7 @@ void AccessorAssembler::HandleLoadField(TNode<JSObject> holder,
Label is_double(this);
TNode<HeapObject> properties = LoadFastProperties(holder);
TNode<Object> value = LoadObjectField(properties, offset);
GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
GotoIf(IsSetWord32<LoadHandler::IsDoubleBits>(handler_word), &is_double);
exit_point->Return(value);
BIND(&is_double);
@ -430,15 +430,14 @@ void AccessorAssembler::HandleLoadWasmField(
}
void AccessorAssembler::HandleLoadWasmField(
TNode<WasmObject> holder, TNode<WordT> handler_word,
TNode<WasmObject> holder, TNode<Word32T> handler_word,
TVariable<Float64T>* var_double_value, Label* rebox_double,
ExitPoint* exit_point) {
Comment("LoadWasmField");
TNode<Int32T> wasm_value_type =
Signed(DecodeWord32<LoadHandler::WasmFieldTypeBits>(
TruncateWordToInt32(handler_word)));
TNode<IntPtrT> field_offset =
Signed(DecodeWord<LoadHandler::WasmFieldOffsetBits>(handler_word));
Signed(DecodeWord32<LoadHandler::WasmFieldTypeBits>(handler_word));
TNode<IntPtrT> field_offset = Signed(
DecodeWordFromWord32<LoadHandler::WasmFieldOffsetBits>(handler_word));
HandleLoadWasmField(holder, wasm_value_type, field_offset, var_double_value,
rebox_double, exit_point);
@ -465,9 +464,9 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
TVARIABLE(Float64T, var_double_value);
Label rebox_double(this, &var_double_value);
TNode<IntPtrT> handler_word = SmiUntag(smi_handler);
TNode<IntPtrT> handler_kind =
Signed(DecodeWord<LoadHandler::KindBits>(handler_word));
TNode<Int32T> handler_word = SmiToInt32(smi_handler);
TNode<Uint32T> handler_kind =
DecodeWord32<LoadHandler::KindBits>(handler_word);
if (support_elements == kSupportElements) {
Label if_element(this), if_indexed_string(this), if_property(this),
@ -475,13 +474,13 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
if_oob(this, Label::kDeferred), try_string_to_array_index(this),
emit_element_load(this);
TVARIABLE(IntPtrT, var_intptr_index);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kElement)), &if_element);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kElement)), &if_element);
if (access_mode == LoadAccessMode::kHas) {
CSA_DCHECK(this, WordNotEqual(handler_kind, LOAD_KIND(kIndexedString)));
CSA_DCHECK(this, Word32NotEqual(handler_kind, LOAD_KIND(kIndexedString)));
Goto(&if_property);
} else {
Branch(WordEqual(handler_kind, LOAD_KIND(kIndexedString)),
Branch(Word32Equal(handler_kind, LOAD_KIND(kIndexedString)),
&if_indexed_string, &if_property);
}
@ -489,7 +488,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
{
Comment("element_load");
// TODO(ishell): implement
CSA_DCHECK(this, IsClearWord<LoadHandler::IsWasmArrayBits>(handler_word));
CSA_DCHECK(this,
IsClearWord32<LoadHandler::IsWasmArrayBits>(handler_word));
TVARIABLE(Int32T, var_instance_type);
TNode<IntPtrT> intptr_index = TryToIntptr(
p->name(), &try_string_to_array_index, &var_instance_type);
@ -515,9 +515,9 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
BIND(&emit_element_load);
{
TNode<BoolT> is_jsarray_condition =
IsSetWord<LoadHandler::IsJsArrayBits>(handler_word);
IsSetWord32<LoadHandler::IsJsArrayBits>(handler_word);
TNode<Uint32T> elements_kind =
DecodeWord32FromWord<LoadHandler::ElementsKindBits>(handler_word);
DecodeWord32<LoadHandler::ElementsKindBits>(handler_word);
EmitElementLoad(CAST(holder), elements_kind, var_intptr_index.value(),
is_jsarray_condition, &if_hole, &rebox_double,
&var_double_value, &unimplemented_elements_kind,
@ -540,7 +540,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
// Check if we're allowed to handle OOB accesses.
TNode<BoolT> allow_out_of_bounds =
IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
IsSetWord32<LoadHandler::AllowOutOfBoundsBits>(handler_word);
GotoIfNot(allow_out_of_bounds, miss);
// Negative indices aren't valid array indices (according to
@ -574,7 +574,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
{
Comment("convert hole");
GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
GotoIfNot(IsSetWord32<LoadHandler::ConvertHoleBits>(handler_word), miss);
GotoIf(IsNoElementsProtectorCellInvalid(), miss);
exit_point->Return(access_mode == LoadAccessMode::kHas
? FalseConstant()
@ -607,7 +607,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), miss);
}
TNode<BoolT> allow_out_of_bounds =
IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
IsSetWord32<LoadHandler::AllowOutOfBoundsBits>(handler_word);
GotoIfNot(allow_out_of_bounds, miss);
GotoIf(IsNoElementsProtectorCellInvalid(), miss);
Return(UndefinedConstant());
@ -630,10 +630,10 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
const LazyLoadICParameters* p, TNode<Object> holder,
TNode<IntPtrT> handler_kind, TNode<WordT> handler_word, Label* rebox_double,
TVariable<Float64T>* var_double_value, TNode<Object> handler, Label* miss,
ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
ElementSupport support_elements) {
TNode<Uint32T> handler_kind, TNode<Word32T> handler_word,
Label* rebox_double, TVariable<Float64T>* var_double_value,
TNode<Object> handler, Label* miss, ExitPoint* exit_point, ICMode ic_mode,
OnNonExistent on_nonexistent, ElementSupport support_elements) {
Label constant(this), field(this), normal(this, Label::kDeferred),
slow(this, Label::kDeferred), interceptor(this, Label::kDeferred),
nonexistent(this), accessor(this, Label::kDeferred),
@ -642,41 +642,43 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
native_data_property(this, Label::kDeferred),
api_getter(this, Label::kDeferred);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kField)), &field);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kField)), &field);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kConstantFromPrototype)), &constant);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kConstantFromPrototype)),
&constant);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kNonExistent)), &nonexistent);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNonExistent)), &nonexistent);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kNormal)), &normal);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNormal)), &normal);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kAccessor)), &accessor);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kAccessor)), &accessor);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kNativeDataProperty)),
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNativeDataProperty)),
&native_data_property);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kApiGetter)), &api_getter);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kApiGetter)), &api_getter);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kApiGetterHolderIsPrototype)),
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kApiGetterHolderIsPrototype)),
&api_getter);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kGlobal)), &global);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kGlobal)), &global);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kSlow)), &slow);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kSlow)), &slow);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kProxy)), &proxy);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kProxy)), &proxy);
Branch(WordEqual(handler_kind, LOAD_KIND(kModuleExport)), &module_export,
Branch(Word32Equal(handler_kind, LOAD_KIND(kModuleExport)), &module_export,
&interceptor);
BIND(&field);
{
#if V8_ENABLE_WEBASSEMBLY
Label is_wasm_field(this);
GotoIf(IsSetWord<LoadHandler::IsWasmStructBits>(handler_word),
GotoIf(IsSetWord32<LoadHandler::IsWasmStructBits>(handler_word),
&is_wasm_field);
#else
CSA_DCHECK(this, IsClearWord<LoadHandler::IsWasmStructBits>(handler_word));
CSA_DCHECK(this,
IsClearWord32<LoadHandler::IsWasmStructBits>(handler_word));
#endif // V8_ENABLE_WEBASSEMBLY
HandleLoadField(CAST(holder), handler_word, var_double_value, rebox_double,
@ -731,7 +733,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
{
Comment("accessor_load");
TNode<IntPtrT> descriptor =
Signed(DecodeWord<LoadHandler::DescriptorBits>(handler_word));
Signed(DecodeWordFromWord32<LoadHandler::DescriptorBits>(handler_word));
TNode<AccessorPair> accessor_pair =
CAST(LoadDescriptorValue(LoadMap(CAST(holder)), descriptor));
TNode<Object> getter =
@ -847,7 +849,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
{
Comment("module export");
TNode<UintPtrT> index =
DecodeWord<LoadHandler::ExportsIndexBits>(handler_word);
DecodeWordFromWord32<LoadHandler::ExportsIndexBits>(handler_word);
TNode<Module> module =
LoadObjectField<Module>(CAST(holder), JSModuleNamespace::kModuleOffset);
TNode<ObjectHashTable> exports =
@ -873,32 +875,34 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
const LazyLoadICParameters* p, TNode<Object> holder,
TNode<IntPtrT> handler_kind, Label* miss, ExitPoint* exit_point,
TNode<Uint32T> handler_kind, Label* miss, ExitPoint* exit_point,
ICMode ic_mode) {
Label return_true(this), return_false(this), return_lookup(this),
normal(this), global(this), slow(this);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kField)), &return_true);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kField)), &return_true);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kConstantFromPrototype)),
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kConstantFromPrototype)),
&return_true);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kNonExistent)), &return_false);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNonExistent)), &return_false);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kNormal)), &normal);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNormal)), &normal);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kAccessor)), &return_true);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kAccessor)), &return_true);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kNativeDataProperty)), &return_true);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kApiGetter)), &return_true);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kApiGetterHolderIsPrototype)),
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNativeDataProperty)),
&return_true);
GotoIf(WordEqual(handler_kind, LOAD_KIND(kSlow)), &slow);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kApiGetter)), &return_true);
Branch(WordEqual(handler_kind, LOAD_KIND(kGlobal)), &global, &return_lookup);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kApiGetterHolderIsPrototype)),
&return_true);
GotoIf(Word32Equal(handler_kind, LOAD_KIND(kSlow)), &slow);
Branch(Word32Equal(handler_kind, LOAD_KIND(kGlobal)), &global,
&return_lookup);
BIND(&return_true);
exit_point->Return(TrueConstant());
@ -908,11 +912,11 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
BIND(&return_lookup);
{
CSA_DCHECK(
this,
Word32Or(WordEqual(handler_kind, LOAD_KIND(kInterceptor)),
Word32Or(WordEqual(handler_kind, LOAD_KIND(kProxy)),
WordEqual(handler_kind, LOAD_KIND(kModuleExport)))));
CSA_DCHECK(this,
Word32Or(Word32Equal(handler_kind, LOAD_KIND(kInterceptor)),
Word32Or(Word32Equal(handler_kind, LOAD_KIND(kProxy)),
Word32Equal(handler_kind,
LOAD_KIND(kModuleExport)))));
exit_point->ReturnCallStub(
Builtins::CallableFor(isolate(), Builtin::kHasProperty), p->context(),
p->receiver(), p->name());
@ -1111,9 +1115,9 @@ void AccessorAssembler::HandleLoadICProtoHandler(
{
// If the "maybe_holder_or_constant" in the handler is a smi, then it's
// guaranteed that it's not a holder object, but a constant value.
CSA_DCHECK(this, WordEqual(Signed(DecodeWord<LoadHandler::KindBits>(
SmiUntag(smi_handler))),
LOAD_KIND(kConstantFromPrototype)));
CSA_DCHECK(this, Word32Equal(DecodeWord32<LoadHandler::KindBits>(
SmiToInt32(smi_handler)),
LOAD_KIND(kConstantFromPrototype)));
if (access_mode == LoadAccessMode::kHas) {
exit_point->Return(TrueConstant());
} else {

View File

@ -379,15 +379,16 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
void HandleLoadCallbackProperty(const LazyLoadICParameters* p,
TNode<JSObject> holder,
TNode<WordT> handler_word,
TNode<Word32T> handler_word,
ExitPoint* exit_point);
void HandleLoadAccessor(const LazyLoadICParameters* p,
TNode<CallHandlerInfo> call_handler_info,
TNode<WordT> handler_word, TNode<DataHandler> handler,
TNode<IntPtrT> handler_kind, ExitPoint* exit_point);
TNode<Word32T> handler_word,
TNode<DataHandler> handler,
TNode<Uint32T> handler_kind, ExitPoint* exit_point);
void HandleLoadField(TNode<JSObject> holder, TNode<WordT> handler_word,
void HandleLoadField(TNode<JSObject> holder, TNode<Word32T> handler_word,
TVariable<Float64T>* var_double_value,
Label* rebox_double, Label* miss, ExitPoint* exit_point);
@ -398,7 +399,8 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TVariable<Float64T>* var_double_value,
Label* rebox_double, ExitPoint* exit_point);
void HandleLoadWasmField(TNode<WasmObject> holder, TNode<WordT> handler_word,
void HandleLoadWasmField(TNode<WasmObject> holder,
TNode<Word32T> handler_word,
TVariable<Float64T>* var_double_value,
Label* rebox_double, ExitPoint* exit_point);
#endif // V8_ENABLE_WEBASSEMBLY
@ -409,14 +411,14 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
void HandleLoadICSmiHandlerLoadNamedCase(
const LazyLoadICParameters* p, TNode<Object> holder,
TNode<IntPtrT> handler_kind, TNode<WordT> handler_word,
TNode<Uint32T> handler_kind, TNode<Word32T> handler_word,
Label* rebox_double, TVariable<Float64T>* var_double_value,
TNode<Object> handler, Label* miss, ExitPoint* exit_point, ICMode ic_mode,
OnNonExistent on_nonexistent, ElementSupport support_elements);
void HandleLoadICSmiHandlerHasNamedCase(const LazyLoadICParameters* p,
TNode<Object> holder,
TNode<IntPtrT> handler_kind,
TNode<Uint32T> handler_kind,
Label* miss, ExitPoint* exit_point,
ICMode ic_mode);