Commit 6b663123 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] allow expressions for array lengths

This allows arbitrary expressions to specify the length of an array.
These expressions get access to globally declared things and the
preceding fields of the current object.
Unfortunately, this breaks generated C++ runtime code, so as a
workaround, I special-case expressions that are just an identifier
and handle them as before. We might want to support more cases there
in the future, probably also with special-casing since having a full
C++ back-end for Torque is infeasible.

Bug: v8:10004 v8:7793

Change-Id: I0d5d1200c0e727766beed7bfb2d43a8abb9cacf0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1942610
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65427}
parent a1a87800
...@@ -868,7 +868,7 @@ struct Annotation { ...@@ -868,7 +868,7 @@ struct Annotation {
struct ClassFieldExpression { struct ClassFieldExpression {
NameAndTypeExpression name_and_type; NameAndTypeExpression name_and_type;
base::Optional<std::string> index; base::Optional<Expression*> index;
std::vector<ConditionalAnnotation> conditions; std::vector<ConditionalAnnotation> conditions;
bool weak; bool weak;
bool const_qualified; bool const_qualified;
......
...@@ -242,6 +242,7 @@ void GenerateFieldValueAccessor(const Field& field, ...@@ -242,6 +242,7 @@ void GenerateFieldValueAccessor(const Field& field,
// std::move(descriptors_struct_field_list), // Struct fields // std::move(descriptors_struct_field_list), // Struct fields
// GetArrayKind(indexed_field_count.validity))); // Field kind // GetArrayKind(indexed_field_count.validity))); // Field kind
void GenerateGetPropsChunkForField(const Field& field, void GenerateGetPropsChunkForField(const Field& field,
base::Optional<NameAndType> array_length,
std::ostream& get_props_impl) { std::ostream& get_props_impl) {
DebugFieldType debug_field_type(field); DebugFieldType debug_field_type(field);
...@@ -272,8 +273,8 @@ void GenerateGetPropsChunkForField(const Field& field, ...@@ -272,8 +273,8 @@ void GenerateGetPropsChunkForField(const Field& field,
// If the field is indexed, emit a fetch of the array length, and change // If the field is indexed, emit a fetch of the array length, and change
// count_value and property_kind to be the correct values for an array. // count_value and property_kind to be the correct values for an array.
if (field.index) { if (array_length) {
const Type* index_type = field.index->type; const Type* index_type = array_length->type;
std::string index_type_name; std::string index_type_name;
if (index_type == TypeOracle::GetSmiType()) { if (index_type == TypeOracle::GetSmiType()) {
index_type_name = "uintptr_t"; index_type_name = "uintptr_t";
...@@ -288,7 +289,8 @@ void GenerateGetPropsChunkForField(const Field& field, ...@@ -288,7 +289,8 @@ void GenerateGetPropsChunkForField(const Field& field,
} }
get_props_impl << " Value<" << index_type_name get_props_impl << " Value<" << index_type_name
<< "> indexed_field_count = Get" << "> indexed_field_count = Get"
<< CamelifyString(field.index->name) << "Value(accessor);\n"; << CamelifyString(array_length->name)
<< "Value(accessor);\n";
property_kind = "GetArrayKind(indexed_field_count.validity)"; property_kind = "GetArrayKind(indexed_field_count.validity)";
} }
...@@ -396,7 +398,15 @@ void GenerateClassDebugReader(const ClassType& type, std::ostream& h_contents, ...@@ -396,7 +398,15 @@ void GenerateClassDebugReader(const ClassType& type, std::ostream& h_contents,
if (field.name_and_type.type == TypeOracle::GetVoidType()) continue; if (field.name_and_type.type == TypeOracle::GetVoidType()) continue;
GenerateFieldAddressAccessor(field, name, h_contents, cc_contents); GenerateFieldAddressAccessor(field, name, h_contents, cc_contents);
GenerateFieldValueAccessor(field, name, h_contents, cc_contents); GenerateFieldValueAccessor(field, name, h_contents, cc_contents);
GenerateGetPropsChunkForField(field, get_props_impl); base::Optional<NameAndType> array_length;
if (field.index) {
array_length = ExtractSimpleFieldArraySize(type, *field.index);
if (!array_length) {
// Unsupported complex array length, skipping this field.
continue;
}
}
GenerateGetPropsChunkForField(field, array_length, get_props_impl);
} }
h_contents << "};\n"; h_contents << "};\n";
......
...@@ -1266,16 +1266,40 @@ void ImplementationVisitor::InitializeClass( ...@@ -1266,16 +1266,40 @@ void ImplementationVisitor::InitializeClass(
} }
} }
VisitResult ImplementationVisitor::GenerateArrayLength(
Expression* array_length, Namespace* nspace,
const std::map<std::string, LocationReference>& bindings) {
StackScope stack_scope(this);
// Switch to the namespace where the class was declared.
CurrentScope::Scope current_scope_scope(nspace);
// Reset local bindings and install local binding for the preceding fields.
BindingsManagersScope bindings_managers_scope;
BlockBindings<LocalValue> field_bindings(&ValueBindingsManager::Get());
for (auto& p : bindings) {
field_bindings.Add(p.first, LocalValue{p.second}, true);
}
VisitResult length = Visit(array_length);
VisitResult converted_length =
GenerateCall("Convert", Arguments{{length}, {}},
{TypeOracle::GetIntPtrType(), length.type()}, false);
return stack_scope.Yield(converted_length);
}
VisitResult ImplementationVisitor::GenerateArrayLength(VisitResult object, VisitResult ImplementationVisitor::GenerateArrayLength(VisitResult object,
const Field& field) { const Field& field) {
DCHECK(field.index); DCHECK(field.index);
StackScope stack_scope(this); StackScope stack_scope(this);
VisitResult length = GenerateFetchFromLocation(GenerateFieldReference( const ClassType* class_type = *object.type()->ClassSupertype();
object, *field.index, *object.type()->ClassSupertype())); std::map<std::string, LocationReference> bindings;
length = GenerateCall("Convert", Arguments{{length}, {}}, for (Field f : class_type->ComputeAllFields()) {
{TypeOracle::GetIntPtrType(), length.type()}, false); if (f.index) break;
return stack_scope.Yield(length); bindings.insert({f.name_and_type.name,
GenerateFieldReference(object, f.name_and_type,
*object.type()->ClassSupertype())});
}
return stack_scope.Yield(
GenerateArrayLength(*field.index, class_type->nspace(), bindings));
} }
VisitResult ImplementationVisitor::GenerateArrayLength( VisitResult ImplementationVisitor::GenerateArrayLength(
...@@ -1284,11 +1308,16 @@ VisitResult ImplementationVisitor::GenerateArrayLength( ...@@ -1284,11 +1308,16 @@ VisitResult ImplementationVisitor::GenerateArrayLength(
DCHECK(field.index); DCHECK(field.index);
StackScope stack_scope(this); StackScope stack_scope(this);
VisitResult length = std::map<std::string, LocationReference> bindings;
initializer_results.field_value_map.at(field.index->name); for (Field f : class_type->ComputeAllFields()) {
length = GenerateCall("Convert", Arguments{{length}, {}}, if (f.index) break;
{TypeOracle::GetIntPtrType(), length.type()}, false); const std::string& fieldname = f.name_and_type.name;
return stack_scope.Yield(length); VisitResult value = initializer_results.field_value_map.at(fieldname);
bindings.insert({fieldname, LocationReference::Temporary(
value, "initial field " + fieldname)});
}
return stack_scope.Yield(
GenerateArrayLength(*field.index, class_type->nspace(), bindings));
} }
VisitResult ImplementationVisitor::GenerateObjectSize( VisitResult ImplementationVisitor::GenerateObjectSize(
...@@ -3653,24 +3682,32 @@ void GenerateClassFieldVerifier(const std::string& class_name, ...@@ -3653,24 +3682,32 @@ void GenerateClassFieldVerifier(const std::string& class_name,
if (TypeOracle::GetUninitializedType()->IsSubtypeOf(field_type)) return; if (TypeOracle::GetUninitializedType()->IsSubtypeOf(field_type)) return;
if (f.index) { if (f.index) {
const Type* index_type = f.index->type; base::Optional<NameAndType> array_length =
std::string index_offset = ExtractSimpleFieldArraySize(class_type, *f.index);
class_name + "::k" + CamelifyString(f.index->name) + "Offset"; if (!array_length) {
Error("Cannot generate verifier for array field with complex length.")
.Position((*f.index)->pos)
.Throw();
}
std::string length_field_offset =
class_name + "::k" + CamelifyString(array_length->name) + "Offset";
cc_contents << " for (int i = 0; i < "; cc_contents << " for (int i = 0; i < ";
if (index_type == TypeOracle::GetSmiType()) { if (array_length->type == TypeOracle::GetSmiType()) {
// We already verified the index field because it was listed earlier, so // We already verified the index field because it was listed earlier, so
// we can assume it's safe to read here. // we can assume it's safe to read here.
cc_contents << "TaggedField<Smi, " << index_offset cc_contents << "TaggedField<Smi, " << length_field_offset
<< ">::load(o).value()"; << ">::load(o).value()";
} else { } else {
const Type* constexpr_version = index_type->ConstexprVersion(); const Type* constexpr_version = array_length->type->ConstexprVersion();
if (constexpr_version == nullptr) { if (constexpr_version == nullptr) {
Error("constexpr representation for type ", index_type->ToString(), Error("constexpr representation for type ",
array_length->type->ToString(),
" is required due to usage as index") " is required due to usage as index")
.Position(f.pos); .Position(f.pos);
} }
cc_contents << "o.ReadField<" << constexpr_version->GetGeneratedTypeName() cc_contents << "o.ReadField<" << constexpr_version->GetGeneratedTypeName()
<< ">(" << index_offset << ")"; << ">(" << length_field_offset << ")";
} }
cc_contents << "; ++i) {\n"; cc_contents << "; ++i) {\n";
} else { } else {
......
...@@ -373,6 +373,9 @@ class ImplementationVisitor { ...@@ -373,6 +373,9 @@ class ImplementationVisitor {
LocationReference GenerateFieldReference(VisitResult object, LocationReference GenerateFieldReference(VisitResult object,
const NameAndType& field, const NameAndType& field,
const ClassType* class_type); const ClassType* class_type);
VisitResult GenerateArrayLength(
Expression* array_length, Namespace* nspace,
const std::map<std::string, LocationReference>& bindings);
VisitResult GenerateArrayLength(VisitResult object, const Field& field); VisitResult GenerateArrayLength(VisitResult object, const Field& field);
VisitResult GenerateArrayLength(const ClassType* class_type, VisitResult GenerateArrayLength(const ClassType* class_type,
const InitializerResults& initializer_results, const InitializerResults& initializer_results,
......
...@@ -1559,7 +1559,7 @@ base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) { ...@@ -1559,7 +1559,7 @@ base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
auto weak = child_results->NextAs<bool>(); auto weak = child_results->NextAs<bool>();
auto const_qualified = child_results->NextAs<bool>(); auto const_qualified = child_results->NextAs<bool>();
auto name = child_results->NextAs<Identifier*>(); auto name = child_results->NextAs<Identifier*>();
auto index = child_results->NextAs<base::Optional<std::string>>(); auto index = child_results->NextAs<base::Optional<Expression*>>();
auto type = child_results->NextAs<TypeExpression*>(); auto type = child_results->NextAs<TypeExpression*>();
return ParseResult{ClassFieldExpression{{name, type}, return ParseResult{ClassFieldExpression{{name, type},
index, index,
...@@ -1692,6 +1692,9 @@ struct TorqueGrammar : Grammar { ...@@ -1692,6 +1692,9 @@ struct TorqueGrammar : Grammar {
TorqueGrammar() : Grammar(&file) { SetWhitespace(MatchWhitespace); } TorqueGrammar() : Grammar(&file) { SetWhitespace(MatchWhitespace); }
// Result: Expression*
Symbol* expression = &assignmentExpression;
// Result: std::string // Result: std::string
Symbol identifier = {Rule({Pattern(MatchIdentifier)}, YieldMatchedInput), Symbol identifier = {Rule({Pattern(MatchIdentifier)}, YieldMatchedInput),
Rule({Token("runtime")}, YieldMatchedInput)}; Rule({Token("runtime")}, YieldMatchedInput)};
...@@ -1818,14 +1821,17 @@ struct TorqueGrammar : Grammar { ...@@ -1818,14 +1821,17 @@ struct TorqueGrammar : Grammar {
// Result: NameAndTypeExpression // Result: NameAndTypeExpression
Symbol nameAndType = {Rule({&name, Token(":"), &type}, MakeNameAndType)}; Symbol nameAndType = {Rule({&name, Token(":"), &type}, MakeNameAndType)};
// Result: base::Optional<Expression*>
Symbol* optionalArraySpecifier = Symbol* optionalArraySpecifier =
Optional<std::string>(Sequence({Token("["), &identifier, Token("]")})); Optional<Expression*>(Sequence({Token("["), expression, Token("]")}));
// Result: ClassFieldExpression
Symbol classField = { Symbol classField = {
Rule({annotations, CheckIf(Token("weak")), CheckIf(Token("const")), &name, Rule({annotations, CheckIf(Token("weak")), CheckIf(Token("const")), &name,
optionalArraySpecifier, Token(":"), &type, Token(";")}, optionalArraySpecifier, Token(":"), &type, Token(";")},
MakeClassField)}; MakeClassField)};
// Result: StructFieldExpression
Symbol structField = { Symbol structField = {
Rule({CheckIf(Token("const")), &name, Token(":"), &type, Token(";")}, Rule({CheckIf(Token("const")), &name, Token(":"), &type, Token(";")},
MakeStructField)}; MakeStructField)};
...@@ -1866,9 +1872,6 @@ struct TorqueGrammar : Grammar { ...@@ -1866,9 +1872,6 @@ struct TorqueGrammar : Grammar {
return result; return result;
} }
// Result: Expression*
Symbol* expression = &assignmentExpression;
// Result: IncrementDecrementOperator // Result: IncrementDecrementOperator
Symbol incrementDecrementOperator = { Symbol incrementDecrementOperator = {
Rule({Token("++")}, Rule({Token("++")},
......
...@@ -433,7 +433,7 @@ void TypeVisitor::VisitClassFieldsAndMethods( ...@@ -433,7 +433,7 @@ void TypeVisitor::VisitClassFieldsAndMethods(
} }
} }
} }
base::Optional<NameAndType> index_field; base::Optional<Expression*> array_length;
if (field_expression.index) { if (field_expression.index) {
if (seen_indexed_field || if (seen_indexed_field ||
(super_class && super_class->HasIndexedField())) { (super_class && super_class->HasIndexedField())) {
...@@ -441,8 +441,7 @@ void TypeVisitor::VisitClassFieldsAndMethods( ...@@ -441,8 +441,7 @@ void TypeVisitor::VisitClassFieldsAndMethods(
"only one indexable field is currently supported per class"); "only one indexable field is currently supported per class");
} }
seen_indexed_field = true; seen_indexed_field = true;
index_field = class_type->LookupFieldInternal(*field_expression.index) array_length = *field_expression.index;
.name_and_type;
} else { } else {
if (seen_indexed_field) { if (seen_indexed_field) {
ReportError("cannot declare non-indexable field \"", ReportError("cannot declare non-indexable field \"",
...@@ -454,7 +453,7 @@ void TypeVisitor::VisitClassFieldsAndMethods( ...@@ -454,7 +453,7 @@ void TypeVisitor::VisitClassFieldsAndMethods(
const Field& field = class_type->RegisterField( const Field& field = class_type->RegisterField(
{field_expression.name_and_type.name->pos, {field_expression.name_and_type.name->pos,
class_type, class_type,
index_field, array_length,
{field_expression.name_and_type.name->value, field_type}, {field_expression.name_and_type.name->value, field_type},
class_offset, class_offset,
field_expression.weak, field_expression.weak,
......
...@@ -800,6 +800,17 @@ bool IsAllowedAsBitField(const Type* type) { ...@@ -800,6 +800,17 @@ bool IsAllowedAsBitField(const Type* type) {
type->IsSubtypeOf(TypeOracle::GetBoolType()); type->IsSubtypeOf(TypeOracle::GetBoolType());
} }
base::Optional<NameAndType> ExtractSimpleFieldArraySize(
const ClassType& class_type, Expression* array_size) {
IdentifierExpression* identifier =
IdentifierExpression::DynamicCast(array_size);
if (!identifier || !identifier->generic_arguments.empty() ||
!identifier->namespace_qualification.empty())
return {};
if (!class_type.HasField(identifier->name->value)) return {};
return class_type.LookupField(identifier->name->value).name_and_type;
}
} // namespace torque } // namespace torque
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -190,7 +190,7 @@ struct Field { ...@@ -190,7 +190,7 @@ struct Field {
SourcePosition pos; SourcePosition pos;
const AggregateType* aggregate; const AggregateType* aggregate;
base::Optional<NameAndType> index; base::Optional<Expression*> index;
NameAndType name_and_type; NameAndType name_and_type;
// The byte offset of this field from the beginning of the containing class or // The byte offset of this field from the beginning of the containing class or
...@@ -789,6 +789,9 @@ base::Optional<std::tuple<size_t, std::string>> SizeOf(const Type* type); ...@@ -789,6 +789,9 @@ base::Optional<std::tuple<size_t, std::string>> SizeOf(const Type* type);
bool IsAnyUnsignedInteger(const Type* type); bool IsAnyUnsignedInteger(const Type* type);
bool IsAllowedAsBitField(const Type* type); bool IsAllowedAsBitField(const Type* type);
base::Optional<NameAndType> ExtractSimpleFieldArraySize(
const ClassType& class_type, Expression* array_size);
} // namespace torque } // namespace torque
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
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