Commit d7e02ea4 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] add const references and disallow const class field writes

- Allow type expression for abstract type supertypes.
  For consistency, and ease of implementation, also allow this for enums.
- Allow subtyping of structs. This requires changing all places where we
  checked for struct types and instead check if we have a subtype of a
  struct type.
- This allows defining two subtypes of the Reference<T> struct for
  mutable and constant references. Mutable references are a subtype of
  constant references.
- &T desugars to MutableReference<T>
  const &T desugars to ConstReference<T>
- A const field of a class produces a constant reference.
  A const field of a mutable reference to a struct is const.
  A mutable field of a const reference to a struct is const.
- It is possible to assign a new struct value to a mutable reference to
  a struct, even if the struct contains const fields. This is analogous
  to allowing assignments of let-bound structs with constant fields.

Not in this CL:
- A notion of const slices.
- Applying const to appropriate class fields.

Bug: v8:7793
Change-Id: I6e7b09d44f54db25f8bf812be5f3b554b80414e0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2096615Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66759}
parent 3e1b6b40
......@@ -17,13 +17,12 @@ namespace torque_internal {
const offset: intptr;
unsafeMarker: Unsafe;
}
type ConstReference<T: type> extends Reference<T>;
type MutableReference<T: type> extends ConstReference<T>;
macro UnsafeNewReference<T: type>(object: HeapObject, offset: intptr):&T {
return Reference<T>{
object: object,
offset: offset,
unsafeMarker: Unsafe {}
};
return %RawDownCast<&T>(
Reference<T>{object: object, offset: offset, unsafeMarker: Unsafe {}});
}
struct Slice<T: type> {
......
......@@ -629,6 +629,8 @@ struct BasicTypeExpression : TypeExpression {
is_constexpr(IsConstexprName(name)),
name(std::move(name)),
generic_arguments(std::move(generic_arguments)) {}
BasicTypeExpression(SourcePosition pos, std::string name)
: BasicTypeExpression(pos, {}, std::move(name), {}) {}
std::vector<std::string> namespace_qualification;
bool is_constexpr;
std::string name;
......@@ -838,7 +840,7 @@ struct InstanceTypeConstraints {
struct AbstractTypeDeclaration : TypeDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(AbstractTypeDeclaration)
AbstractTypeDeclaration(SourcePosition pos, Identifier* name, bool transient,
base::Optional<Identifier*> extends,
base::Optional<TypeExpression*> extends,
base::Optional<std::string> generates)
: TypeDeclaration(kKind, pos, name),
is_constexpr(IsConstexprName(name->value)),
......@@ -847,7 +849,7 @@ struct AbstractTypeDeclaration : TypeDeclaration {
generates(std::move(generates)) {}
bool is_constexpr;
bool transient;
base::Optional<Identifier*> extends;
base::Optional<TypeExpression*> extends;
base::Optional<std::string> generates;
};
......
......@@ -44,8 +44,8 @@ class ValueTypeFieldIterator {
int shift_bits;
};
const Result operator*() const {
if (const StructType* struct_type = StructType::DynamicCast(type_)) {
const auto& field = struct_type->fields()[index_];
if (auto struct_type = type_->StructSupertype()) {
const auto& field = (*struct_type)->fields()[index_];
return {field.name_and_type, field.pos, *field.offset, 0, 0};
}
const Type* type = type_;
......@@ -87,9 +87,9 @@ class ValueTypeFieldsRange {
ValueTypeFieldIterator begin() { return {type_, 0}; }
ValueTypeFieldIterator end() {
size_t index = 0;
const StructType* struct_type = StructType::DynamicCast(type_);
if (struct_type && struct_type != TypeOracle::GetFloat64OrHoleType()) {
index = struct_type->fields().size();
base::Optional<const StructType*> struct_type = type_->StructSupertype();
if (struct_type && *struct_type != TypeOracle::GetFloat64OrHoleType()) {
index = (*struct_type)->fields().size();
}
const Type* type = type_;
if (const auto type_wrapped_in_smi =
......@@ -142,7 +142,7 @@ class DebugFieldType {
// object types that are not included in the compilation of the debug helper
// library.
std::string GetOriginalType(TypeStorage storage) const {
if (name_and_type_.type->IsStructType()) {
if (name_and_type_.type->StructSupertype()) {
// There's no meaningful type we could use here, because the V8 symbols
// don't have any definition of a C++ struct matching this struct type.
return "";
......@@ -259,7 +259,7 @@ void GenerateFieldValueAccessor(const Field& field,
std::ostream& h_contents,
std::ostream& cc_contents) {
// Currently not implemented for struct fields.
if (field.name_and_type.type->IsStructType()) return;
if (field.name_and_type.type->StructSupertype()) return;
DebugFieldType debug_field_type(field);
......@@ -274,25 +274,23 @@ void GenerateFieldValueAccessor(const Field& field,
index_offset = " + offset * sizeof(value)";
}
if (!field.name_and_type.type->IsStructType()) {
std::string field_value_type = debug_field_type.GetValueType(kUncompressed);
h_contents << " Value<" << field_value_type << "> " << field_getter
<< "(d::MemoryAccessor accessor " << index_param << ") const;\n";
cc_contents << "\nValue<" << field_value_type << "> Tq" << class_name
<< "::" << field_getter << "(d::MemoryAccessor accessor"
<< index_param << ") const {\n";
cc_contents << " " << debug_field_type.GetValueType(kAsStoredInHeap)
<< " value{};\n";
cc_contents << " d::MemoryAccessResult validity = accessor("
<< address_getter << "()" << index_offset
<< ", reinterpret_cast<uint8_t*>(&value), sizeof(value));\n";
cc_contents << " return {validity, "
<< (debug_field_type.IsTagged()
? "EnsureDecompressed(value, address_)"
: "value")
<< "};\n";
cc_contents << "}\n";
}
std::string field_value_type = debug_field_type.GetValueType(kUncompressed);
h_contents << " Value<" << field_value_type << "> " << field_getter
<< "(d::MemoryAccessor accessor " << index_param << ") const;\n";
cc_contents << "\nValue<" << field_value_type << "> Tq" << class_name
<< "::" << field_getter << "(d::MemoryAccessor accessor"
<< index_param << ") const {\n";
cc_contents << " " << debug_field_type.GetValueType(kAsStoredInHeap)
<< " value{};\n";
cc_contents << " d::MemoryAccessResult validity = accessor("
<< address_getter << "()" << index_offset
<< ", reinterpret_cast<uint8_t*>(&value), sizeof(value));\n";
cc_contents << " return {validity, "
<< (debug_field_type.IsTagged()
? "EnsureDecompressed(value, address_)"
: "value")
<< "};\n";
cc_contents << "}\n";
}
// Emits a portion of the member function GetProperties that is responsible for
......
......@@ -63,7 +63,8 @@ static const char* const CONST_INT31_TYPE_STRING = "constexpr int31";
static const char* const CONST_INT32_TYPE_STRING = "constexpr int32";
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 MUTABLE_REFERENCE_TYPE_STRING = "MutableReference";
static const char* const CONST_REFERENCE_TYPE_STRING = "ConstReference";
static const char* const SLICE_TYPE_STRING = "Slice";
static const char* const WEAK_TYPE_STRING = "Weak";
static const char* const SMI_TAGGED_TYPE_STRING = "SmiTagged";
......
......@@ -6,6 +6,7 @@
#include "src/common/globals.h"
#include "src/torque/type-oracle.h"
#include "src/torque/types.h"
#include "src/torque/utils.h"
namespace v8 {
......@@ -181,7 +182,7 @@ void CSAGenerator::EmitInstruction(
}
out() << " ";
if (type->IsStructType()) {
if (type->StructSupertype()) {
out() << "std::tie(";
PrintCommaSeparatedList(out(), results);
out() << ") = ";
......@@ -189,7 +190,7 @@ void CSAGenerator::EmitInstruction(
out() << results[0] << " = ";
}
out() << instruction.constant->external_name() << "(state_)";
if (type->IsStructType()) {
if (type->StructSupertype()) {
out() << ".Flatten();\n";
} else {
out() << ";\n";
......@@ -239,7 +240,7 @@ void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction,
}
out() << " ";
if (return_type->IsStructType()) {
if (return_type->StructSupertype()) {
out() << "std::tie(";
PrintCommaSeparatedList(out(), results);
out() << ") = ";
......@@ -262,8 +263,9 @@ void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction,
ReportError("%RawDownCast error: ", *return_type, " is not a subtype of ",
*original_type);
}
if (return_type->GetGeneratedTNodeTypeName() !=
original_type->GetGeneratedTNodeTypeName()) {
if (!original_type->StructSupertype() &&
return_type->GetGeneratedTNodeTypeName() !=
original_type->GetGeneratedTNodeTypeName()) {
if (return_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
out() << "TORQUE_CAST";
} else {
......@@ -318,7 +320,7 @@ void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction,
if (instruction.intrinsic->ExternalName() == "%FromConstexpr") {
out() << ")";
}
if (return_type->IsStructType()) {
if (return_type->StructSupertype()) {
out() << ").Flatten();\n";
} else {
out() << ");\n";
......@@ -349,7 +351,7 @@ void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction,
std::string catch_name =
PreCallableExceptionPreparation(instruction.catch_block);
out() << " ";
bool needs_flattening = return_type->IsStructType();
bool needs_flattening = return_type->StructSupertype().has_value();
if (needs_flattening) {
out() << "std::tie(";
PrintCommaSeparatedList(out(), results);
......@@ -448,7 +450,7 @@ void CSAGenerator::EmitInstruction(
out() << ", &" << var_names[i][j];
}
}
if (return_type->IsStructType()) {
if (return_type->StructSupertype()) {
out() << ").Flatten();\n";
} else {
out() << ");\n";
......@@ -931,10 +933,10 @@ void CSAGenerator::EmitCSAValue(VisitResult result,
std::ostream& out) {
if (!result.IsOnStack()) {
out << result.constexpr_value();
} else if (auto* struct_type = StructType::DynamicCast(result.type())) {
out << struct_type->GetGeneratedTypeName() << "{";
} else if (auto struct_type = result.type()->StructSupertype()) {
out << (*struct_type)->GetGeneratedTypeName() << "{";
bool first = true;
for (auto& field : struct_type->fields()) {
for (auto& field : (*struct_type)->fields()) {
if (!first) {
out << ", ";
}
......
......@@ -340,7 +340,7 @@ class Macro : public Callable {
bool ShouldBeInlined() const override {
for (const LabelDeclaration& label : signature().labels) {
for (const Type* type : label.types) {
if (type->IsStructType()) return true;
if (type->StructSupertype()) return true;
}
}
// Intrinsics that are used internally in Torque and implemented as torque
......
......@@ -91,18 +91,16 @@ Builtin* DeclarationVisitor::CreateBuiltin(BuiltinDeclaration* decl,
}
for (size_t i = 0; i < signature.types().size(); ++i) {
if (const StructType* type =
StructType::DynamicCast(signature.types()[i])) {
Error("Builtin '", decl->name, "' uses the struct '", type->name(),
"' as argument '", signature.parameter_names[i],
"', which is not supported.");
if (signature.types()[i]->StructSupertype()) {
Error("Builtin do not support structs as arguments, but argument ",
signature.parameter_names[i], " has type ", *signature.types()[i],
".");
}
}
if (const StructType* struct_type =
StructType::DynamicCast(signature.return_type)) {
Error("Builtins ", decl->name, " cannot return structs ",
struct_type->name());
if (signature.return_type->StructSupertype()) {
Error("Builtins cannot return structs, but the return type is ",
*signature.return_type, ".");
}
return Declarations::CreateBuiltin(std::move(external_name),
......
This diff is collapsed.
......@@ -55,8 +55,7 @@ class LocationReference {
// pointer.
static LocationReference HeapReference(VisitResult heap_reference) {
LocationReference result;
DCHECK(Type::MatchUnaryGeneric(heap_reference.type(),
TypeOracle::GetReferenceGeneric()));
DCHECK(TypeOracle::MatchReferenceGeneric(heap_reference.type()));
result.heap_reference_ = std::move(heap_reference);
return result;
}
......@@ -92,7 +91,17 @@ class LocationReference {
return result;
}
bool IsConst() const { return temporary_.has_value(); }
bool IsConst() const {
if (IsHeapReference()) {
bool is_const;
bool success =
TypeOracle::MatchReferenceGeneric(heap_reference().type(), &is_const)
.has_value();
CHECK(success);
return is_const;
}
return IsTemporary();
}
bool IsVariableAccess() const { return variable_.has_value(); }
const VisitResult& variable() const {
......@@ -130,8 +139,7 @@ class LocationReference {
const Type* ReferencedType() const {
if (IsHeapReference()) {
return *Type::MatchUnaryGeneric(heap_reference().type(),
TypeOracle::GetReferenceGeneric());
return *TypeOracle::MatchReferenceGeneric(heap_reference().type());
}
if (IsHeapSlice()) {
return *Type::MatchUnaryGeneric(heap_slice().type(),
......@@ -360,7 +368,7 @@ inline bool Binding<LocalValue>::CheckWritten() const {
auto binding = *manager_->current_bindings_[name_];
const LocationReference& ref = binding->value;
if (!ref.IsVariableAccess()) return false;
return !ref.GetVisitResult().type()->IsStructType();
return !ref.GetVisitResult().type()->StructSupertype();
}
template <>
inline std::string Binding<LocalLabel>::BindingTypeString() const {
......@@ -411,7 +419,7 @@ class ImplementationVisitor {
LocationReference GenerateFieldReference(VisitResult object,
const Field& field,
const ClassType* class_type);
LocationReference GenerateFieldReference(
LocationReference GenerateFieldReferenceForInit(
VisitResult object, const Field& field,
const LayoutForInitialization& layout);
VisitResult GenerateArrayLength(
......@@ -437,6 +445,7 @@ class ImplementationVisitor {
LocationReference GetLocationReference(FieldAccessExpression* expr);
LocationReference GenerateFieldAccess(
LocationReference reference, const std::string& fieldname,
bool ignore_stuct_field_constness = false,
base::Optional<SourcePosition> pos = {});
LocationReference GetLocationReference(ElementAccessExpression* expr);
......
......@@ -9,6 +9,7 @@
#include <unordered_map>
#include "src/flags/flags.h"
#include "src/torque/ast.h"
#include "src/torque/constants.h"
#include "src/torque/declarations.h"
#include "src/torque/earley-parser.h"
......@@ -302,6 +303,14 @@ void CheckNotDeferredStatement(Statement* statement) {
}
}
TypeExpression* AddConstexpr(TypeExpression* type) {
BasicTypeExpression* basic = BasicTypeExpression::DynamicCast(type);
if (!basic) Error("Unsupported extends clause.").Throw();
return MakeNode<BasicTypeExpression>(basic->namespace_qualification,
CONSTEXPR_TYPE_PREFIX + basic->name,
basic->generic_arguments);
}
Expression* MakeCall(IdentifierExpression* callee,
base::Optional<Expression*> target,
std::vector<Expression*> arguments,
......@@ -661,7 +670,7 @@ base::Optional<ParseResult> MakeAbstractTypeDeclaration(
NamingConventionError("Type", name, "UpperCamelCase");
}
auto generic_parameters = child_results->NextAs<GenericParameters>();
auto extends = child_results->NextAs<base::Optional<Identifier*>>();
auto extends = child_results->NextAs<base::Optional<TypeExpression*>>();
auto generates = child_results->NextAs<base::Optional<std::string>>();
TypeDeclaration* type_decl = MakeNode<AbstractTypeDeclaration>(
name, transient, extends, std::move(generates));
......@@ -680,11 +689,9 @@ base::Optional<ParseResult> MakeAbstractTypeDeclaration(
MakeNode<Identifier>(CONSTEXPR_TYPE_PREFIX + name->value);
constexpr_name->pos = name->pos;
base::Optional<Identifier*> constexpr_extends;
base::Optional<TypeExpression*> constexpr_extends;
if (extends) {
constexpr_extends =
MakeNode<Identifier>(CONSTEXPR_TYPE_PREFIX + (*extends)->value);
(*constexpr_extends)->pos = name->pos;
constexpr_extends = AddConstexpr(*extends);
}
TypeDeclaration* constexpr_decl = MakeNode<AbstractTypeDeclaration>(
constexpr_name, transient, constexpr_extends, constexpr_generates);
......@@ -1090,12 +1097,15 @@ base::Optional<ParseResult> MakeFunctionTypeExpression(
base::Optional<ParseResult> MakeReferenceTypeExpression(
ParseResultIterator* child_results) {
auto is_const = child_results->NextAs<bool>();
auto referenced_type = child_results->NextAs<TypeExpression*>();
std::vector<std::string> namespace_qualification{
TORQUE_INTERNAL_NAMESPACE_STRING};
std::vector<TypeExpression*> generic_arguments{referenced_type};
TypeExpression* result = MakeNode<BasicTypeExpression>(
namespace_qualification, REFERENCE_TYPE_STRING, generic_arguments);
namespace_qualification,
is_const ? CONST_REFERENCE_TYPE_STRING : MUTABLE_REFERENCE_TYPE_STRING,
generic_arguments);
return ParseResult{result};
}
......@@ -1149,7 +1159,8 @@ base::Optional<ParseResult> MakeEnumDeclaration(
const bool is_extern = child_results->NextAs<bool>();
auto name_identifier = child_results->NextAs<Identifier*>();
auto name = name_identifier->value;
auto base_identifier = child_results->NextAs<base::Optional<Identifier*>>();
auto base_type_expression =
child_results->NextAs<base::Optional<TypeExpression*>>();
auto constexpr_generates_opt =
child_results->NextAs<base::Optional<std::string>>();
auto entries = child_results->NextAs<std::vector<Identifier*>>();
......@@ -1167,12 +1178,12 @@ base::Optional<ParseResult> MakeEnumDeclaration(
auto constexpr_generates =
constexpr_generates_opt ? *constexpr_generates_opt : name;
const bool generate_nonconstexpr = base_identifier.has_value();
const bool generate_nonconstexpr = base_type_expression.has_value();
std::vector<Declaration*> result;
// Build non-constexpr types.
if (generate_nonconstexpr) {
DCHECK(base_identifier.has_value());
DCHECK(base_type_expression.has_value());
if (is_open) {
// For open enumerations, we define an abstract type and inherit all
......@@ -1184,12 +1195,16 @@ base::Optional<ParseResult> MakeEnumDeclaration(
// type kEntryN extends Enum;
// }
auto type_decl = MakeNode<AbstractTypeDeclaration>(
name_identifier, false, base_identifier, base::nullopt);
name_identifier, false, base_type_expression, base::nullopt);
TypeExpression* name_type_expression =
MakeNode<BasicTypeExpression>(name_identifier->value);
name_type_expression->pos = name_identifier->pos;
std::vector<Declaration*> entry_decls;
for (const auto& entry_name_identifier : entries) {
entry_decls.push_back(MakeNode<AbstractTypeDeclaration>(
entry_name_identifier, false, name_identifier, base::nullopt));
entry_name_identifier, false, name_type_expression, base::nullopt));
}
result.push_back(type_decl);
......@@ -1208,7 +1223,7 @@ base::Optional<ParseResult> MakeEnumDeclaration(
std::vector<Declaration*> entry_decls;
for (const auto& entry_name_identifier : entries) {
entry_decls.push_back(MakeNode<AbstractTypeDeclaration>(
entry_name_identifier, false, base_identifier, base::nullopt));
entry_name_identifier, false, base_type_expression, base::nullopt));
auto entry_type = MakeNode<BasicTypeExpression>(
std::vector<std::string>{name}, entry_name_identifier->value,
......@@ -1238,13 +1253,15 @@ base::Optional<ParseResult> MakeEnumDeclaration(
// }
Identifier* constexpr_type_identifier =
MakeNode<Identifier>(std::string(CONSTEXPR_TYPE_PREFIX) + name);
base::Optional<Identifier*> base_constexpr_type_identifier = base::nullopt;
if (base_identifier) {
base_constexpr_type_identifier = MakeNode<Identifier>(
std::string(CONSTEXPR_TYPE_PREFIX) + (*base_identifier)->value);
TypeExpression* constexpr_type_expression = MakeNode<BasicTypeExpression>(
std::string(CONSTEXPR_TYPE_PREFIX) + name);
base::Optional<TypeExpression*> base_constexpr_type_expression =
base::nullopt;
if (base_type_expression) {
base_constexpr_type_expression = AddConstexpr(*base_type_expression);
}
result.push_back(MakeNode<AbstractTypeDeclaration>(
constexpr_type_identifier, false, base_constexpr_type_identifier,
constexpr_type_identifier, false, base_constexpr_type_expression,
constexpr_generates));
TypeExpression* type_expr = nullptr;
......@@ -1252,10 +1269,7 @@ base::Optional<ParseResult> MakeEnumDeclaration(
Identifier* fromconstexpr_parameter_identifier = nullptr;
Statement* fromconstexpr_body = nullptr;
if (generate_nonconstexpr) {
DCHECK(base_identifier.has_value());
TypeExpression* base_type_expr = MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, (*base_identifier)->value,
std::vector<TypeExpression*>{});
DCHECK(base_type_expression.has_value());
type_expr = MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, name, std::vector<TypeExpression*>{});
......@@ -1268,7 +1282,7 @@ base::Optional<ParseResult> MakeEnumDeclaration(
std::vector<TypeExpression*>{type_expr},
std::vector<Expression*>{MakeNode<IntrinsicCallExpression>(
MakeNode<Identifier>("%FromConstexpr"),
std::vector<TypeExpression*>{base_type_expr},
std::vector<TypeExpression*>{*base_type_expression},
std::vector<Expression*>{MakeNode<IdentifierExpression>(
std::vector<std::string>{},
fromconstexpr_parameter_identifier)})}));
......@@ -1286,7 +1300,7 @@ base::Optional<ParseResult> MakeEnumDeclaration(
entry_decls.push_back(MakeNode<AbstractTypeDeclaration>(
MakeNode<Identifier>(entry_constexpr_type), false,
constexpr_type_identifier, constexpr_generates));
constexpr_type_expression, constexpr_generates));
// namespace Enum {
// const kEntry0: constexpr kEntry0 constexpr 'Enum::kEntry0';
......@@ -1972,7 +1986,8 @@ struct TorqueGrammar : Grammar {
Rule({Token("builtin"), Token("("), typeList, Token(")"), Token("=>"),
&simpleType},
MakeFunctionTypeExpression),
Rule({Token("&"), &simpleType}, MakeReferenceTypeExpression)};
Rule({CheckIf(Token("const")), Token("&"), &simpleType},
MakeReferenceTypeExpression)};
// Result: TypeExpression*
Symbol type = {Rule({&simpleType}), Rule({&type, Token("|"), &simpleType},
......@@ -2356,7 +2371,7 @@ struct TorqueGrammar : Grammar {
AsSingletonVector<Declaration*, MakeBitFieldStructDeclaration>()),
Rule({CheckIf(Token("transient")), Token("type"), &name,
TryOrDefault<GenericParameters>(&genericParameters),
Optional<Identifier*>(Sequence({Token("extends"), &name})),
Optional<TypeExpression*>(Sequence({Token("extends"), &type})),
Optional<std::string>(
Sequence({Token("generates"), &externalString})),
Optional<std::string>(
......@@ -2406,7 +2421,7 @@ struct TorqueGrammar : Grammar {
Rule({Token("#include"), &externalString},
AsSingletonVector<Declaration*, MakeCppIncludeDeclaration>()),
Rule({CheckIf(Token("extern")), Token("enum"), &name,
Optional<Identifier*>(Sequence({Token("extends"), &name})),
Optional<TypeExpression*>(Sequence({Token("extends"), &type})),
Optional<std::string>(
Sequence({Token("constexpr"), &externalString})),
Token("{"), NonemptyList<Identifier*>(&name, Token(",")),
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "src/torque/type-oracle.h"
#include "src/base/optional.h"
#include "src/torque/type-visitor.h"
#include "src/torque/types.h"
......@@ -80,6 +81,21 @@ std::vector<const ClassType*> TypeOracle::GetClasses() {
return result;
}
base::Optional<const Type*> TypeOracle::MatchReferenceGeneric(
const Type* reference_type, bool* is_const) {
if (auto type = Type::MatchUnaryGeneric(reference_type,
GetMutableReferenceGeneric())) {
if (is_const) *is_const = false;
return type;
}
if (auto type =
Type::MatchUnaryGeneric(reference_type, GetConstReferenceGeneric())) {
if (is_const) *is_const = true;
return type;
}
return base::nullopt;
}
} // namespace torque
} // namespace internal
} // namespace v8
......@@ -81,11 +81,22 @@ class TypeOracle : public ContextualClass<TypeOracle> {
static const Type* GetGenericTypeInstance(GenericType* generic_type,
TypeVector arg_types);
static GenericType* GetReferenceGeneric() {
return Declarations::LookupUniqueGenericType(QualifiedName(
{TORQUE_INTERNAL_NAMESPACE_STRING}, REFERENCE_TYPE_STRING));
static GenericType* GetReferenceGeneric(bool is_const) {
return Declarations::LookupUniqueGenericType(
QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING},
is_const ? CONST_REFERENCE_TYPE_STRING
: MUTABLE_REFERENCE_TYPE_STRING));
}
static GenericType* GetConstReferenceGeneric() {
return GetReferenceGeneric(true);
}
static GenericType* GetMutableReferenceGeneric() {
return GetReferenceGeneric(false);
}
static base::Optional<const Type*> MatchReferenceGeneric(
const Type* reference_type, bool* is_const = nullptr);
static GenericType* GetSliceGeneric() {
return Declarations::LookupUniqueGenericType(
QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING}, SLICE_TYPE_STRING));
......@@ -99,8 +110,16 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return Declarations::LookupGlobalUniqueGenericType(SMI_TAGGED_TYPE_STRING);
}
static const Type* GetReferenceType(const Type* referenced_type) {
return GetGenericTypeInstance(GetReferenceGeneric(), {referenced_type});
static const Type* GetReferenceType(const Type* referenced_type,
bool is_const) {
return GetGenericTypeInstance(GetReferenceGeneric(is_const),
{referenced_type});
}
static const Type* GetConstReferenceType(const Type* referenced_type) {
return GetReferenceType(referenced_type, true);
}
static const Type* GetMutableReferenceType(const Type* referenced_type) {
return GetReferenceType(referenced_type, false);
}
static const Type* GetSliceType(const Type* referenced_type) {
......
......@@ -81,7 +81,7 @@ const AbstractType* TypeVisitor::ComputeType(
const Type* parent_type = nullptr;
if (decl->extends) {
parent_type = Declarations::LookupType(*decl->extends);
parent_type = TypeVisitor::ComputeType(*decl->extends);
if (parent_type->IsUnionType()) {
// UnionType::IsSupertypeOf requires that types can only extend from non-
// union types in order to work correctly.
......@@ -90,10 +90,6 @@ const AbstractType* TypeVisitor::ComputeType(
}
}
if (generates == "" && parent_type) {
generates = parent_type->GetGeneratedTNodeTypeName();
}
if (decl->is_constexpr && decl->transient) {
ReportError("cannot declare a transient type that is also constexpr");
}
......
......@@ -113,6 +113,15 @@ base::Optional<const ClassType*> Type::ClassSupertype() const {
return base::nullopt;
}
base::Optional<const StructType*> Type::StructSupertype() const {
for (const Type* t = this; t != nullptr; t = t->parent()) {
if (auto* struct_type = StructType::DynamicCast(t)) {
return struct_type;
}
}
return base::nullopt;
}
// static
const Type* Type::CommonSupertype(const Type* a, const Type* b) {
int diff = a->Depth() - b->Depth();
......@@ -161,6 +170,7 @@ std::string Type::GetGeneratedTNodeTypeName() const {
}
std::string AbstractType::GetGeneratedTNodeTypeNameImpl() const {
if (generated_type_.empty()) return parent()->GetGeneratedTNodeTypeName();
return generated_type_;
}
......@@ -391,9 +401,8 @@ StructType::Classification StructType::ClassifyContents() const {
const Type* field_type = struct_field.name_and_type.type;
if (field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
result |= ClassificationFlag::kTagged;
} else if (const StructType* field_as_struct =
StructType::DynamicCast(field_type)) {
result |= field_as_struct->ClassifyContents();
} else if (auto field_as_struct = field_type->StructSupertype()) {
result |= (*field_as_struct)->ClassifyContents();
} else {
result |= ClassificationFlag::kUntagged;
}
......@@ -405,6 +414,12 @@ StructType::Classification StructType::ClassifyContents() const {
std::string Type::ComputeName(const std::string& basename,
MaybeSpecializationKey specialized_from) {
if (!specialized_from) return basename;
if (specialized_from->generic == TypeOracle::GetConstReferenceGeneric()) {
return torque::ToString("const &", *specialized_from->specialized_types[0]);
}
if (specialized_from->generic == TypeOracle::GetMutableReferenceGeneric()) {
return torque::ToString("&", *specialized_from->specialized_types[0]);
}
std::stringstream s;
s << basename << "<";
bool first = true;
......@@ -572,33 +587,35 @@ void ClassType::GenerateAccessors() {
load_signature, load_body, base::nullopt);
// Store accessor
IdentifierExpression* value = MakeNode<IdentifierExpression>(
std::vector<std::string>{}, MakeNode<Identifier>(std::string{"v"}));
std::string store_macro_name = "Store" + this->name() + camel_field_name;
Signature store_signature;
store_signature.parameter_names.push_back(MakeNode<Identifier>("o"));
store_signature.parameter_types.types.push_back(this);
if (field.index) {
store_signature.parameter_names.push_back(MakeNode<Identifier>("i"));
store_signature.parameter_types.types.push_back(
TypeOracle::GetIntPtrType());
}
store_signature.parameter_names.push_back(MakeNode<Identifier>("v"));
store_signature.parameter_types.types.push_back(field.name_and_type.type);
store_signature.parameter_types.var_args = false;
// TODO(danno): Store macros probably should return their value argument
store_signature.return_type = TypeOracle::GetVoidType();
Expression* store_expression = MakeNode<FieldAccessExpression>(
parameter, MakeNode<Identifier>(field.name_and_type.name));
if (field.index) {
store_expression =
MakeNode<ElementAccessExpression>(store_expression, index);
if (!field.const_qualified) {
IdentifierExpression* value = MakeNode<IdentifierExpression>(
std::vector<std::string>{}, MakeNode<Identifier>(std::string{"v"}));
std::string store_macro_name = "Store" + this->name() + camel_field_name;
Signature store_signature;
store_signature.parameter_names.push_back(MakeNode<Identifier>("o"));
store_signature.parameter_types.types.push_back(this);
if (field.index) {
store_signature.parameter_names.push_back(MakeNode<Identifier>("i"));
store_signature.parameter_types.types.push_back(
TypeOracle::GetIntPtrType());
}
store_signature.parameter_names.push_back(MakeNode<Identifier>("v"));
store_signature.parameter_types.types.push_back(field.name_and_type.type);
store_signature.parameter_types.var_args = false;
// TODO(danno): Store macros probably should return their value argument
store_signature.return_type = TypeOracle::GetVoidType();
Expression* store_expression = MakeNode<FieldAccessExpression>(
parameter, MakeNode<Identifier>(field.name_and_type.name));
if (field.index) {
store_expression =
MakeNode<ElementAccessExpression>(store_expression, index);
}
Statement* store_body = MakeNode<ExpressionStatement>(
MakeNode<AssignmentExpression>(store_expression, value));
Declarations::DeclareMacro(store_macro_name, true, base::nullopt,
store_signature, store_body, base::nullopt,
false);
}
Statement* store_body = MakeNode<ExpressionStatement>(
MakeNode<AssignmentExpression>(store_expression, value));
Declarations::DeclareMacro(store_macro_name, true, base::nullopt,
store_signature, store_body, base::nullopt,
false);
}
}
......@@ -715,7 +732,7 @@ VisitResult ProjectStructField(VisitResult structure,
BottomOffset begin = structure.stack_range().begin();
// Check constructor this super classes for fields.
const StructType* type = StructType::cast(structure.type());
const StructType* type = *structure.type()->StructSupertype();
auto& fields = type->fields();
for (auto& field : fields) {
BottomOffset end = begin + LoweredSlotCount(field.name_and_type.type);
......@@ -734,8 +751,8 @@ void AppendLoweredTypes(const Type* type, std::vector<const Type*>* result) {
DCHECK_NE(type, TypeOracle::GetNeverType());
if (type->IsConstexpr()) return;
if (type == TypeOracle::GetVoidType()) return;
if (auto* s = StructType::DynamicCast(type)) {
for (const Field& field : s->fields()) {
if (base::Optional<const StructType*> s = type->StructSupertype()) {
for (const Field& field : (*s)->fields()) {
AppendLoweredTypes(field.name_and_type.type, result);
}
} else {
......@@ -838,9 +855,9 @@ size_t StructType::AlignmentLog2() const {
void Field::ValidateAlignment(ResidueClass at_offset) const {
const Type* type = name_and_type.type;
const StructType* struct_type = StructType::DynamicCast(type);
base::Optional<const StructType*> struct_type = type->StructSupertype();
if (struct_type && struct_type != TypeOracle::GetFloat64OrHoleType()) {
for (const Field& field : struct_type->fields()) {
for (const Field& field : (*struct_type)->fields()) {
field.ValidateAlignment(at_offset);
size_t field_size = std::get<0>(field.GetFieldSizeInformation());
at_offset += field_size;
......@@ -894,12 +911,12 @@ base::Optional<std::tuple<size_t, std::string>> SizeOf(const Type* type) {
} else if (type->IsSubtypeOf(TypeOracle::GetUIntPtrType())) {
size = TargetArchitecture::RawPtrSize();
size_string = "kIntptrSize";
} else if (const StructType* struct_type = StructType::DynamicCast(type)) {
} else if (auto struct_type = type->StructSupertype()) {
if (type == TypeOracle::GetFloat64OrHoleType()) {
size = kDoubleSize;
size_string = "kDoubleSize";
} else {
size = struct_type->PackedSize();
size = (*struct_type)->PackedSize();
size_string = std::to_string(size);
}
} else {
......
......@@ -133,6 +133,7 @@ class V8_EXPORT_PRIVATE Type : public TypeBase {
virtual const Type* NonConstexprVersion() const { return this; }
std::string GetConstexprGeneratedTypeName() const;
base::Optional<const ClassType*> ClassSupertype() const;
base::Optional<const StructType*> StructSupertype() const;
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)); }
......@@ -258,6 +259,9 @@ class AbstractType final : public Type {
const std::string& name() const { return name_; }
std::string ToExplicitString() const override { return name(); }
std::string GetGeneratedTypeNameImpl() const override {
if (generated_type_.empty()) {
return parent()->GetGeneratedTypeName();
}
return IsConstexpr() ? generated_type_ : "TNode<" + generated_type_ + ">";
}
std::string GetGeneratedTNodeTypeNameImpl() const override;
......
......@@ -25,6 +25,9 @@ namespace torque_internal {
const object: HeapObject;
const offset: intptr;
}
type ConstReference<T : type> extends Reference<T>;
type MutableReference<T : type> extends ConstReference<T>;
type UninitializedHeapObject extends HeapObject;
}
......@@ -42,6 +45,7 @@ extern class HeapObject extends StrongTagged {
}
type Map extends HeapObject generates 'TNode<Map>';
type Object = Smi | HeapObject;
type Number = Smi|HeapNumber;
type JSReceiver extends HeapObject generates 'TNode<JSReceiver>';
type JSObject extends JSReceiver generates 'TNode<JSObject>';
type int32 generates 'TNode<Int32T>' constexpr 'int32_t';
......@@ -71,12 +75,17 @@ type BuiltinPtr extends Smi generates 'TNode<BuiltinPtr>';
type Context extends HeapObject generates 'TNode<Context>';
type NativeContext extends Context;
type SmiTagged<T : type extends uint31> extends Smi;
type String extends HeapObject;
type HeapNumber extends HeapObject;
type FixedArrayBase extends HeapObject;
struct float64_or_hole {
is_hole: bool;
value: float64;
}
extern operator '+' macro IntPtrAdd(intptr, intptr): intptr;
intrinsic %FromConstexpr<To: type, From: type>(b: From): To;
intrinsic %RawDownCast<To: type, From: type>(x: From): To;
intrinsic %RawConstexprCast<To: type, From: type>(f: From): To;
......@@ -85,6 +94,7 @@ extern macro TaggedToSmi(Object): Smi
labels CastError;
extern macro TaggedToHeapObject(Object): HeapObject
labels CastError;
extern macro Float64SilenceNaN(float64): float64;
extern macro IntPtrConstant(constexpr int31): intptr;
......@@ -98,6 +108,9 @@ FromConstexpr<Smi, constexpr int31>(s: constexpr int31): Smi {
FromConstexpr<intptr, constexpr int31>(i: constexpr int31): intptr {
return IntPtrConstant(i);
}
FromConstexpr<intptr, constexpr intptr>(i: constexpr intptr): intptr {
return %FromConstexpr<intptr>(i);
}
macro Cast<A : type extends Object>(implicit context: Context)(o: Object): A
labels CastError {
......@@ -614,6 +627,134 @@ TEST(Torque, EnumInTypeswitch) {
)");
}
TEST(Torque, ConstClassFields) {
ExpectSuccessfulCompilation(R"(
class Foo extends HeapObject {
const x: int32;
y: int32;
}
@export
macro Test(implicit context: Context)(o: Foo, n: int32) {
const _x: int32 = o.x;
o.y = n;
}
)");
ExpectFailingCompilation(R"(
class Foo extends HeapObject {
const x: int32;
}
@export
macro Test(implicit context: Context)(o: Foo, n: int32) {
o.x = n;
}
)",
HasSubstr("cannot assign to const value"));
ExpectSuccessfulCompilation(R"(
class Foo extends HeapObject {
s: Bar;
}
struct Bar {
const x: int32;
y: int32;
}
@export
macro Test(implicit context: Context)(o: Foo, n: int32) {
const _x: int32 = o.s.x;
// Assigning a struct as a value is OK, even when the struct contains
// const fields.
o.s = Bar{x: n, y: n};
o.s.y = n;
}
)");
ExpectFailingCompilation(R"(
class Foo extends HeapObject {
const s: Bar;
}
struct Bar {
const x: int32;
y: int32;
}
@export
macro Test(implicit context: Context)(o: Foo, n: int32) {
o.s.y = n;
}
)",
HasSubstr("cannot assign to const value"));
ExpectFailingCompilation(R"(
class Foo extends HeapObject {
s: Bar;
}
struct Bar {
const x: int32;
y: int32;
}
@export
macro Test(implicit context: Context)(o: Foo, n: int32) {
o.s.x = n;
}
)",
HasSubstr("cannot assign to const value"));
}
TEST(Torque, References) {
ExpectSuccessfulCompilation(R"(
class Foo extends HeapObject {
const x: int32;
y: int32;
}
@export
macro Test(implicit context: Context)(o: Foo, n: int32) {
const constRefX: const &int32 = &o.x;
const refY: &int32 = &o.y;
const constRefY: const &int32 = refY;
const _x: int32 = *constRefX;
const _y1: int32 = *refY;
const _y2: int32 = *constRefY;
*refY = n;
let r: const &int32 = constRefX;
r = constRefY;
}
)");
ExpectFailingCompilation(R"(
class Foo extends HeapObject {
const x: int32;
y: int32;
}
@export
macro Test(implicit context: Context)(o: Foo) {
const _refX: &int32 = &o.x;
}
)",
HasSubstr("cannot use expression of type const "
"&int32 as a value of type &int32"));
ExpectFailingCompilation(R"(
class Foo extends HeapObject {
const x: int32;
y: int32;
}
@export
macro Test(implicit context: Context)(o: Foo, n: int32) {
const constRefX: const &int32 = &o.x;
*constRefX = n;
}
)",
HasSubstr("cannot assign to const value"));
}
} // namespace torque
} // namespace internal
} // 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