[maglev] Finish TryBuildPropertyLoad

Implement all PropertyAccessInfo kind for property load.

- Changes if-chain to a switch to make it clear we implemented all
PropertyAccessInfo kinds.
- Adds StringLength to do a Int32 field load.
- Adds UnsafeSmiTag to tag StringLength, since we know it fits in a Smi.

Bug: v8:7700
Change-Id: I671b98ead141efa22beab86094e901c9f0c29928
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3948605
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83648}
This commit is contained in:
Victor Gomes 2022-10-12 13:40:05 +02:00 committed by V8 LUCI CQ
parent a169bab6f7
commit e109d6c702
6 changed files with 103 additions and 19 deletions

View File

@ -28,6 +28,7 @@ namespace internal {
V(kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry, \
"The function_data field should be a BytecodeArray on interpreter entry") \
V(kInputStringTooLong, "Input string too long") \
V(kInputDoesNotFitSmi, "Input number is too large to fit in a Smi") \
V(kInvalidBytecode, "Invalid bytecode") \
V(kInvalidBytecodeAdvance, "Cannot advance current bytecode, ") \
V(kInvalidHandleScopeLevel, "Invalid HandleScope level") \

View File

@ -1290,20 +1290,30 @@ bool MaglevGraphBuilder::TryBuildPropertyLoad(
access_info.holder().value());
}
if (access_info.IsNotFound()) {
SetAccumulator(GetRootConstant(RootIndex::kUndefinedValue));
return true;
} else if (access_info.IsFastAccessorConstant() ||
access_info.IsDictionaryProtoAccessorConstant()) {
return TryBuildPropertyGetterCall(access_info, receiver);
} else if (access_info.IsDataField() || access_info.IsFastDataConstant()) {
BuildLoadField(access_info, lookup_start_object);
return true;
} else if (access_info.IsDictionaryProtoDataConstant()) {
return TryFoldLoadDictPrototypeConstant(access_info);
} else {
// TODO(victorgomes): Add other property access implementation.
return false;
switch (access_info.kind()) {
case compiler::PropertyAccessInfo::kInvalid:
return false;
case compiler::PropertyAccessInfo::kNotFound:
SetAccumulator(GetRootConstant(RootIndex::kUndefinedValue));
return true;
case compiler::PropertyAccessInfo::kDataField:
case compiler::PropertyAccessInfo::kFastDataConstant:
BuildLoadField(access_info, lookup_start_object);
return true;
case compiler::PropertyAccessInfo::kDictionaryProtoDataConstant:
return TryFoldLoadDictPrototypeConstant(access_info);
case compiler::PropertyAccessInfo::kFastAccessorConstant:
case compiler::PropertyAccessInfo::kDictionaryProtoAccessorConstant:
return TryBuildPropertyGetterCall(access_info, receiver);
case compiler::PropertyAccessInfo::kModuleExport: {
ValueNode* cell = GetConstant(access_info.constant().value().AsCell());
SetAccumulator(AddNewNode<LoadTaggedField>({cell}, Cell::kValueOffset));
return true;
}
case compiler::PropertyAccessInfo::kStringLength:
DCHECK_EQ(receiver, lookup_start_object);
SetAccumulator(AddNewNode<StringLength>({receiver}));
return true;
}
}

View File

@ -137,6 +137,7 @@ class MaglevGraphVerifier {
case Opcode::kGetTemplateObject:
case Opcode::kLogicalNot:
case Opcode::kSetPendingMessage:
case Opcode::kStringLength:
case Opcode::kToBooleanLogicalNot:
case Opcode::kTestUndetectable:
case Opcode::kTestTypeOf:
@ -149,6 +150,7 @@ class MaglevGraphVerifier {
break;
case Opcode::kSwitch:
case Opcode::kCheckedSmiTag:
case Opcode::kUnsafeSmiTag:
case Opcode::kChangeInt32ToFloat64:
DCHECK_EQ(node->input_count(), 1);
CheckValueInputIs(node, 0, ValueRepresentation::kInt32);

View File

@ -690,16 +690,24 @@ class MergePointInterpreterFrameState {
ValueRepresentation::kInt32);
DCHECK(!value->properties().is_conversion());
#define IS_INT32_OP_NODE(Name) || value->Is<Name>()
DCHECK(value->Is<Int32Constant>()
DCHECK(value->Is<Int32Constant>() ||
value->Is<StringLength>()
INT32_OPERATIONS_NODE_LIST(IS_INT32_OP_NODE));
#undef IS_INT32_OP_NODE
NodeInfo* node_info = known_node_aspects.GetOrCreateInfoFor(value);
if (!node_info->tagged_alternative) {
// Create a tagged version.
ValueNode* tagged =
Node::New<CheckedSmiTag, std::initializer_list<ValueNode*>>(
compilation_unit.zone(), compilation_unit,
value->eager_deopt_info()->state, {value});
ValueNode* tagged;
if (value->Is<StringLength>()) {
static_assert(String::kMaxLength <= kSmiMaxValue,
"String length must fit into a Smi");
tagged = Node::New<UnsafeSmiTag>(compilation_unit.zone(), {value});
} else {
tagged = Node::New<CheckedSmiTag, std::initializer_list<ValueNode*>>(
compilation_unit.zone(), compilation_unit,
value->eager_deopt_info()->state, {value});
}
Node::List::AddAfter(value, tagged);
compilation_unit.RegisterNodeInGraphLabeller(tagged);
node_info->tagged_alternative = tagged;

View File

@ -1830,6 +1830,25 @@ void SetNamedGeneric::PrintParams(std::ostream& os,
os << "(" << name_ << ")";
}
void StringLength::AllocateVreg(MaglevVregAllocationState* vreg_state) {
UseRegister(object_input());
DefineAsRegister(vreg_state, this);
}
void StringLength::GenerateCode(MaglevAssembler* masm,
const ProcessingState& state) {
Register object = ToRegister(object_input());
if (v8_flags.debug_code) {
// Use return register as temporary.
Register tmp = ToRegister(result());
// Check if {object} is a string.
__ AssertNotSmi(object);
__ LoadMap(tmp, object);
__ CmpInstanceTypeRange(tmp, tmp, FIRST_STRING_TYPE, LAST_STRING_TYPE);
__ Check(below_equal, AbortReason::kUnexpectedValue);
}
__ movl(ToRegister(result()), FieldOperand(object, String::kLengthOffset));
}
void DefineNamedOwnGeneric::AllocateVreg(
MaglevVregAllocationState* vreg_state) {
using D = CallInterfaceDescriptorFor<Builtin::kDefineNamedOwnIC>::type;
@ -2536,6 +2555,19 @@ void CheckedSmiTag::GenerateCode(MaglevAssembler* masm,
__ EmitEagerDeoptIf(overflow, DeoptimizeReason::kOverflow, this);
}
void UnsafeSmiTag::AllocateVreg(MaglevVregAllocationState* vreg_state) {
UseRegister(input());
DefineSameAsFirst(vreg_state, this);
}
void UnsafeSmiTag::GenerateCode(MaglevAssembler* masm,
const ProcessingState& state) {
Register reg = ToRegister(input());
__ addl(reg, reg);
if (v8_flags.debug_code) {
__ Check(no_overflow, AbortReason::kInputDoesNotFitSmi);
}
}
void Int32Constant::AllocateVreg(MaglevVregAllocationState* vreg_state) {
DefineAsConstant(vreg_state, this);
}

View File

@ -160,6 +160,7 @@ class CompactInterpreterFrameState;
V(Phi) \
V(RegisterInput) \
V(CheckedSmiTag) \
V(UnsafeSmiTag) \
V(CheckedSmiUntag) \
V(CheckedInternalizedString) \
V(CheckedObjectToIndex) \
@ -169,6 +170,7 @@ class CompactInterpreterFrameState;
V(CheckedFloat64Unbox) \
V(LogicalNot) \
V(SetPendingMessage) \
V(StringLength) \
V(ToBooleanLogicalNot) \
V(TaggedEqual) \
V(TaggedNotEqual) \
@ -1702,6 +1704,20 @@ class CheckedSmiTag : public FixedInputValueNodeT<1, CheckedSmiTag> {
DECL_NODE_INTERFACE_WITH_EMPTY_PRINT_PARAMS()
};
// Input must guarantee to fit in a Smi.
class UnsafeSmiTag : public FixedInputValueNodeT<1, UnsafeSmiTag> {
using Base = FixedInputValueNodeT<1, UnsafeSmiTag>;
public:
explicit UnsafeSmiTag(uint64_t bitfield) : Base(bitfield) {}
static constexpr OpProperties kProperties = OpProperties::ConversionNode();
Input& input() { return Node::input(0); }
DECL_NODE_INTERFACE_WITH_EMPTY_PRINT_PARAMS()
};
class CheckedSmiUntag : public FixedInputValueNodeT<1, CheckedSmiUntag> {
using Base = FixedInputValueNodeT<1, CheckedSmiUntag>;
@ -3114,6 +3130,21 @@ class SetNamedGeneric : public FixedInputValueNodeT<3, SetNamedGeneric> {
const compiler::FeedbackSource feedback_;
};
class StringLength : public FixedInputValueNodeT<1, StringLength> {
using Base = FixedInputValueNodeT<1, StringLength>;
public:
explicit StringLength(uint64_t bitfield) : Base(bitfield) {}
static constexpr OpProperties kProperties =
OpProperties::Reading() | OpProperties::Int32();
static constexpr int kObjectIndex = 0;
Input& object_input() { return input(kObjectIndex); }
DECL_NODE_INTERFACE_WITH_EMPTY_PRINT_PARAMS()
};
class DefineNamedOwnGeneric
: public FixedInputValueNodeT<3, DefineNamedOwnGeneric> {
using Base = FixedInputValueNodeT<3, DefineNamedOwnGeneric>;