Commit 72d440d9 authored by Seth Brenith's avatar Seth Brenith Committed by Commit Bot

[torque] Strict verification of weak fields

Now that we can represent specific weak types with Weak<T>, this CL
updates the generated verifier functions so that they permit weak
references only to the specified type. As an example, consider the
verifier emitted for the following field in PrototypeInfo:

  object_create_map: Weak<Map>|Undefined;

We used to emit the following, which allowed any weak reference:

  CHECK(object_create_map__value.IsWeakOrCleared()
      || object_create_map__value.GetHeapObjectOrSmi().IsOddball());

With this change, we emit a stricter check:

  CHECK(object_create_map__value.IsCleared()
      || (!object_create_map__value.IsWeak()
          && object_create_map__value.GetHeapObjectOrSmi().IsOddball())
      || (object_create_map__value.IsWeak()
          && object_create_map__value.GetHeapObjectOrSmi().IsMap()));

Bug: v8:7793
Change-Id: I4be236d97dedbcdd6c98207928aee8bda2a77f00
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1914613
Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64965}
parent 908274fc
......@@ -303,12 +303,7 @@ USE_TORQUE_VERIFIER(FreeSpace)
USE_TORQUE_VERIFIER(HeapNumber)
void FeedbackVector::FeedbackVectorVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::FeedbackVectorVerify(*this, isolate);
MaybeObject code = optimized_code_weak_or_smi();
MaybeObject::VerifyMaybeObjectPointer(isolate, code);
CHECK(code->IsSmi() || code->IsWeakOrCleared());
}
USE_TORQUE_VERIFIER(FeedbackVector)
USE_TORQUE_VERIFIER(JSReceiver)
......@@ -513,13 +508,7 @@ void WeakFixedArray::WeakFixedArrayVerify(Isolate* isolate) {
}
}
void WeakArrayList::WeakArrayListVerify(Isolate* isolate) {
VerifySmiField(kCapacityOffset);
VerifySmiField(kLengthOffset);
for (int i = 0; i < length(); i++) {
MaybeObject::VerifyMaybeObjectPointer(isolate, Get(i));
}
}
USE_TORQUE_VERIFIER(WeakArrayList)
void PropertyArray::PropertyArrayVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::PropertyArrayVerify(*this, isolate);
......
......@@ -54,6 +54,7 @@ static const char* const CONST_FLOAT64_TYPE_STRING = "constexpr float64";
static const char* const TORQUE_INTERNAL_NAMESPACE_STRING = "torque_internal";
static const char* const REFERENCE_TYPE_STRING = "Reference";
static const char* const SLICE_TYPE_STRING = "Slice";
static const char* const WEAK_TYPE_STRING = "Weak";
static const char* const GENERIC_TYPE_INSTANTIATION_NAMESPACE_STRING =
"_generic_type_instantiation_namespace";
......
......@@ -137,6 +137,12 @@ GenericType* Declarations::LookupUniqueGenericType(const QualifiedName& name) {
"generic type");
}
GenericType* Declarations::LookupGlobalUniqueGenericType(
const std::string& name) {
return EnsureUnique(FilterDeclarables<GenericType>(LookupGlobalScope(name)),
name, "generic type");
}
base::Optional<GenericType*> Declarations::TryLookupGenericType(
const QualifiedName& name) {
std::vector<GenericType*> results = TryLookup<GenericType>(name);
......
......@@ -76,6 +76,7 @@ class Declarations {
static GenericCallable* LookupUniqueGeneric(const QualifiedName& name);
static GenericType* LookupUniqueGenericType(const QualifiedName& name);
static GenericType* LookupGlobalUniqueGenericType(const std::string& name);
static base::Optional<GenericType*> TryLookupGenericType(
const QualifiedName& name);
......
......@@ -1977,8 +1977,7 @@ LocationReference ImplementationVisitor::GetLocationReference(
LocationReference ImplementationVisitor::GetLocationReference(
DereferenceExpression* expr) {
VisitResult ref = Visit(expr->reference);
if (!StructType::MatchUnaryGeneric(ref.type(),
TypeOracle::GetReferenceGeneric())) {
if (!Type::MatchUnaryGeneric(ref.type(), TypeOracle::GetReferenceGeneric())) {
ReportError("Operator * expects a reference but found a value of type ",
*ref.type());
}
......@@ -3262,9 +3261,9 @@ void CppClassGenerator::GenerateFieldAccessorForObject(const Field& f) {
<< " value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);\n\n";
std::string type_check;
for (const std::string& runtime_type : field_type->GetRuntimeTypes()) {
for (const RuntimeType& runtime_type : field_type->GetRuntimeTypes()) {
if (!type_check.empty()) type_check += " || ";
type_check += "value.Is" + runtime_type + "()";
type_check += "value.Is" + runtime_type.type + "()";
}
// Generate implementation in inline header.
......@@ -3487,15 +3486,34 @@ void GenerateClassFieldVerifier(const std::string& class_name,
// the Object type because it would not check anything beyond what we already
// checked with VerifyPointer.
if (f.name_and_type.type != TypeOracle::GetObjectType()) {
std::string type_check = maybe_object ? value + ".IsWeakOrCleared()" : "";
std::string strong_value =
value + (maybe_object ? ".GetHeapObjectOrSmi()" : "");
for (const std::string& runtime_type : field_type->GetRuntimeTypes()) {
if (runtime_type == "MaybeObject") continue;
if (!type_check.empty()) type_check += " || ";
type_check += strong_value + ".Is" + runtime_type + "()";
}
cc_contents << " CHECK(" << type_check << ");\n";
std::stringstream type_check;
bool at_start = true;
// If weak pointers are allowed, then start by checking for a cleared value.
if (maybe_object) {
type_check << value << ".IsCleared()";
at_start = false;
}
for (const RuntimeType& runtime_type : field_type->GetRuntimeTypes()) {
if (!at_start) type_check << " || ";
at_start = false;
if (maybe_object) {
bool strong = runtime_type.weak_ref_to.empty();
if (strong && runtime_type.type == "MaybeObject") {
// Rather than a generic Weak<T>, this is a basic type Tagged or
// WeakHeapObject. We can't validate anything more about the type of
// the object pointed to, so just check that it's weak.
type_check << value << ".IsWeak()";
} else {
type_check << "(" << (strong ? "!" : "") << value << ".IsWeak() && "
<< value << ".GetHeapObjectOrSmi().Is"
<< (strong ? runtime_type.type : runtime_type.weak_ref_to)
<< "())";
}
} else {
type_check << value << ".Is" << runtime_type.type << "()";
}
}
cc_contents << " CHECK(" << type_check.str() << ");\n";
}
cc_contents << " }\n";
}
......
......@@ -54,8 +54,8 @@ class LocationReference {
// pointer.
static LocationReference HeapReference(VisitResult heap_reference) {
LocationReference result;
DCHECK(StructType::MatchUnaryGeneric(heap_reference.type(),
TypeOracle::GetReferenceGeneric()));
DCHECK(Type::MatchUnaryGeneric(heap_reference.type(),
TypeOracle::GetReferenceGeneric()));
result.heap_reference_ = std::move(heap_reference);
return result;
}
......@@ -63,8 +63,8 @@ class LocationReference {
// encode an inner pointer, and the number of elements.
static LocationReference HeapSlice(VisitResult heap_slice) {
LocationReference result;
DCHECK(StructType::MatchUnaryGeneric(heap_slice.type(),
TypeOracle::GetSliceGeneric()));
DCHECK(Type::MatchUnaryGeneric(heap_slice.type(),
TypeOracle::GetSliceGeneric()));
result.heap_slice_ = std::move(heap_slice);
return result;
}
......@@ -109,11 +109,11 @@ class LocationReference {
const Type* ReferencedType() const {
if (IsHeapReference()) {
return *StructType::MatchUnaryGeneric(heap_reference().type(),
TypeOracle::GetReferenceGeneric());
return *Type::MatchUnaryGeneric(heap_reference().type(),
TypeOracle::GetReferenceGeneric());
} else if (IsHeapSlice()) {
return *StructType::MatchUnaryGeneric(heap_slice().type(),
TypeOracle::GetSliceGeneric());
return *Type::MatchUnaryGeneric(heap_slice().type(),
TypeOracle::GetSliceGeneric());
}
return GetVisitResult().type();
}
......
......@@ -81,6 +81,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING}, SLICE_TYPE_STRING));
}
static GenericType* GetWeakGeneric() {
return Declarations::LookupGlobalUniqueGenericType(WEAK_TYPE_STRING);
}
static const Type* GetReferenceType(const Type* referenced_type) {
return GetGenericTypeInstance(GetReferenceGeneric(), {referenced_type});
}
......
......@@ -136,6 +136,23 @@ std::string AbstractType::GetGeneratedTNodeTypeNameImpl() const {
return generated_type_;
}
std::vector<RuntimeType> AbstractType::GetRuntimeTypes() const {
std::string type_name = GetGeneratedTNodeTypeName();
if (auto strong_type =
Type::MatchUnaryGeneric(this, TypeOracle::GetWeakGeneric())) {
auto strong_runtime_types = (*strong_type)->GetRuntimeTypes();
std::vector<RuntimeType> result;
for (const RuntimeType& type : strong_runtime_types) {
// Generic parameter in Weak<T> should have already been checked to
// extend HeapObject, so it couldn't itself be another weak type.
DCHECK(type.weak_ref_to.empty());
result.push_back({type_name, type.type});
}
return result;
}
return {{type_name, ""}};
}
std::string BuiltinPointerType::ToExplicitString() const {
std::stringstream result;
result << "builtin (";
......@@ -340,17 +357,8 @@ std::string Type::ComputeName(const std::string& basename,
std::string StructType::SimpleNameImpl() const { return decl_->name->value; }
// static
base::Optional<const Type*> StructType::MatchUnaryGeneric(
const Type* type, GenericType* generic) {
if (auto* struct_type = StructType::DynamicCast(type)) {
return MatchUnaryGeneric(struct_type, generic);
}
return base::nullopt;
}
// static
base::Optional<const Type*> StructType::MatchUnaryGeneric(
const StructType* type, GenericType* generic) {
base::Optional<const Type*> Type::MatchUnaryGeneric(const Type* type,
GenericType* generic) {
DCHECK_EQ(generic->generic_parameters().size(), 1);
if (!type->GetSpecializedFrom()) {
return base::nullopt;
......
......@@ -91,6 +91,13 @@ struct SpecializationKey {
using MaybeSpecializationKey = base::Optional<SpecializationKey<GenericType>>;
struct RuntimeType {
std::string type;
// If {type} is "MaybeObject", then {weak_ref_to} indicates the corresponding
// strong object type. Otherwise, {weak_ref_to} is empty.
std::string weak_ref_to;
};
class V8_EXPORT_PRIVATE Type : public TypeBase {
public:
virtual bool IsSubtypeOf(const Type* supertype) const;
......@@ -119,13 +126,15 @@ class V8_EXPORT_PRIVATE Type : public TypeBase {
virtual const Type* NonConstexprVersion() const { return this; }
virtual const Type* ConstexprVersion() const { return nullptr; }
base::Optional<const ClassType*> ClassSupertype() const;
virtual std::vector<std::string> GetRuntimeTypes() const { return {}; }
virtual std::vector<RuntimeType> GetRuntimeTypes() const { return {}; }
static const Type* CommonSupertype(const Type* a, const Type* b);
void AddAlias(std::string alias) const { aliases_.insert(std::move(alias)); }
size_t id() const { return id_; }
const MaybeSpecializationKey& GetSpecializedFrom() const {
return specialized_from_;
}
static base::Optional<const Type*> MatchUnaryGeneric(const Type* type,
GenericType* generic);
protected:
Type(TypeBase::Kind kind, const Type* parent,
......@@ -241,9 +250,7 @@ class AbstractType final : public Type {
return nullptr;
}
std::vector<std::string> GetRuntimeTypes() const override {
return {GetGeneratedTNodeTypeName()};
}
std::vector<RuntimeType> GetRuntimeTypes() const override;
private:
friend class TypeOracle;
......@@ -310,7 +317,9 @@ class V8_EXPORT_PRIVATE BuiltinPointerType final : public Type {
}
size_t function_pointer_type_id() const { return function_pointer_type_id_; }
std::vector<std::string> GetRuntimeTypes() const override { return {"Smi"}; }
std::vector<RuntimeType> GetRuntimeTypes() const override {
return {{"Smi", ""}};
}
private:
friend class TypeOracle;
......@@ -408,10 +417,10 @@ class V8_EXPORT_PRIVATE UnionType final : public Type {
return union_type ? UnionType(*union_type) : UnionType(t);
}
std::vector<std::string> GetRuntimeTypes() const override {
std::vector<std::string> result;
std::vector<RuntimeType> GetRuntimeTypes() const override {
std::vector<RuntimeType> result;
for (const Type* member : types_) {
std::vector<std::string> sub_result = member->GetRuntimeTypes();
std::vector<RuntimeType> sub_result = member->GetRuntimeTypes();
result.insert(result.end(), sub_result.begin(), sub_result.end());
}
return result;
......@@ -460,7 +469,9 @@ class AggregateType : public Type {
std::vector<Method*> Methods(const std::string& name) const;
std::vector<const AggregateType*> GetHierarchy() const;
std::vector<std::string> GetRuntimeTypes() const override { return {name_}; }
std::vector<RuntimeType> GetRuntimeTypes() const override {
return {{name_, ""}};
}
protected:
AggregateType(Kind kind, const Type* parent, Namespace* nspace,
......@@ -492,11 +503,6 @@ class StructType final : public AggregateType {
std::string GetGeneratedTypeNameImpl() const override;
static base::Optional<const Type*> MatchUnaryGeneric(const Type* type,
GenericType* generic);
static base::Optional<const Type*> MatchUnaryGeneric(const StructType* type,
GenericType* generic);
private:
friend class TypeOracle;
StructType(Namespace* nspace, const StructDeclaration* decl,
......
......@@ -28,8 +28,11 @@ namespace torque_internal {
}
type Tagged generates 'TNode<MaybeObject>' constexpr 'MaybeObject';
type StrongTagged extends Tagged generates 'TNode<Object>' constexpr 'ObjectPtr';
type StrongTagged extends Tagged
generates 'TNode<Object>' constexpr 'ObjectPtr';
type Smi extends StrongTagged generates 'TNode<Smi>' constexpr 'Smi';
type WeakHeapObject extends Tagged;
type Weak<T : type extends HeapObject> extends WeakHeapObject;
type Uninitialized extends Tagged;
@abstract
......
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