[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:
parent
a169bab6f7
commit
e109d6c702
@ -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") \
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>;
|
||||
|
Loading…
Reference in New Issue
Block a user