Commit e483fb27 authored by Seth Brenith's avatar Seth Brenith Committed by Commit Bot

[torque] Automatically generate verifier functions

This change generates functions that verify the things that Torque knows
about objects and their fields. We still must implement each verifier
function in objects-debug.cc, but we can call into the generated code to
verify that field types match their Torque definitions. If no additional
verification is required, we can use the macro USE_TORQUE_VERIFIER as a
shorthand for a verifier that calls the corresponding generated
function.

A new annotation @noVerifier can be applied to both class and field
definitions, to prevent generating verification code. This allows fully
customized verification for complicated cases like
JSFunction::prototype_or_initial_map, which might not exist at all, and
JSObject::elements, which might be a one pointer filler map.

Because Factory::InitializeJSObjectFromMap fills new objects with
undefined values, and many verifiers need to deal with partially-
initialized objects, the generated verifiers allow undefined values on
every class deriving from JSObject. In cases where stricter checks were
previously performed, they are kept in objects-debug.cc.

Bug: v8:7793
Change-Id: I84034efadca89ba0aceddf92e886ffbfaa4c23fa
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1594042
Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61422}
parent 41bc1cfd
...@@ -1053,6 +1053,8 @@ action("run_torque") { ...@@ -1053,6 +1053,8 @@ action("run_torque") {
outputs = [ outputs = [
"$target_gen_dir/torque-generated/builtin-definitions-from-dsl.h", "$target_gen_dir/torque-generated/builtin-definitions-from-dsl.h",
"$target_gen_dir/torque-generated/class-definitions-from-dsl.h", "$target_gen_dir/torque-generated/class-definitions-from-dsl.h",
"$target_gen_dir/torque-generated/class-verifiers-from-dsl.cc",
"$target_gen_dir/torque-generated/class-verifiers-from-dsl.h",
"$target_gen_dir/torque-generated/objects-printer-from-dsl.cc", "$target_gen_dir/torque-generated/objects-printer-from-dsl.cc",
] ]
foreach(namespace, torque_namespaces) { foreach(namespace, torque_namespaces) {
...@@ -1119,6 +1121,8 @@ v8_source_set("torque_generated_definitions") { ...@@ -1119,6 +1121,8 @@ v8_source_set("torque_generated_definitions") {
] ]
sources = [ sources = [
"$target_gen_dir/torque-generated/class-verifiers-from-dsl.cc",
"$target_gen_dir/torque-generated/class-verifiers-from-dsl.h",
"$target_gen_dir/torque-generated/objects-printer-from-dsl.cc", "$target_gen_dir/torque-generated/objects-printer-from-dsl.cc",
] ]
......
This diff is collapsed.
This diff is collapsed.
...@@ -121,6 +121,12 @@ bool Object::IsNullOrUndefined() const { ...@@ -121,6 +121,12 @@ bool Object::IsNullOrUndefined() const {
return IsHeapObject() && HeapObject::cast(*this)->IsNullOrUndefined(); return IsHeapObject() && HeapObject::cast(*this)->IsNullOrUndefined();
} }
bool Object::IsZero() const { return *this == Smi::zero(); }
bool Object::IsNoSharedNameSentinel() const {
return *this == SharedFunctionInfo::kNoSharedNameSentinel;
}
bool HeapObject::IsNullOrUndefined(Isolate* isolate) const { bool HeapObject::IsNullOrUndefined(Isolate* isolate) const {
return Object::IsNullOrUndefined(isolate); return Object::IsNullOrUndefined(isolate);
} }
......
...@@ -306,6 +306,9 @@ class Object { ...@@ -306,6 +306,9 @@ class Object {
V8_INLINE bool IsNullOrUndefined(ReadOnlyRoots roots) const; V8_INLINE bool IsNullOrUndefined(ReadOnlyRoots roots) const;
V8_INLINE bool IsNullOrUndefined() const; V8_INLINE bool IsNullOrUndefined() const;
V8_INLINE bool IsZero() const;
V8_INLINE bool IsNoSharedNameSentinel() const;
enum class Conversion { kToNumber, kToNumeric }; enum class Conversion { kToNumber, kToNumeric };
#define DECL_STRUCT_PREDICATE(NAME, Name, name) V8_INLINE bool Is##Name() const; #define DECL_STRUCT_PREDICATE(NAME, Name, name) V8_INLINE bool Is##Name() const;
......
...@@ -201,6 +201,8 @@ class FixedArray : public FixedArrayBase { ...@@ -201,6 +201,8 @@ class FixedArray : public FixedArrayBase {
using BodyDescriptor = FlexibleBodyDescriptor<kHeaderSize>; using BodyDescriptor = FlexibleBodyDescriptor<kHeaderSize>;
static constexpr int kObjectsOffset = kHeaderSize;
protected: protected:
// Set operation on FixedArray without using write barriers. Can // Set operation on FixedArray without using write barriers. Can
// only be used for storing old space objects or smis. // only be used for storing old space objects or smis.
......
...@@ -721,6 +721,7 @@ struct ClassFieldExpression { ...@@ -721,6 +721,7 @@ struct ClassFieldExpression {
base::Optional<std::string> conditional; base::Optional<std::string> conditional;
bool weak; bool weak;
bool const_qualified; bool const_qualified;
bool generate_verify;
}; };
struct LabelAndTypes { struct LabelAndTypes {
...@@ -924,7 +925,7 @@ struct StructDeclaration : TypeDeclaration { ...@@ -924,7 +925,7 @@ struct StructDeclaration : TypeDeclaration {
struct ClassDeclaration : TypeDeclaration { struct ClassDeclaration : TypeDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ClassDeclaration) DEFINE_AST_NODE_LEAF_BOILERPLATE(ClassDeclaration)
ClassDeclaration(SourcePosition pos, Identifier* name, bool is_extern, ClassDeclaration(SourcePosition pos, Identifier* name, bool is_extern,
bool generate_print, bool transient, bool generate_print, bool generate_verify, bool transient,
base::Optional<TypeExpression*> super, base::Optional<TypeExpression*> super,
base::Optional<std::string> generates, base::Optional<std::string> generates,
std::vector<Declaration*> methods, std::vector<Declaration*> methods,
...@@ -932,6 +933,7 @@ struct ClassDeclaration : TypeDeclaration { ...@@ -932,6 +933,7 @@ struct ClassDeclaration : TypeDeclaration {
: TypeDeclaration(kKind, pos, name), : TypeDeclaration(kKind, pos, name),
is_extern(is_extern), is_extern(is_extern),
generate_print(generate_print), generate_print(generate_print),
generate_verify(generate_verify),
transient(transient), transient(transient),
super(super), super(super),
generates(std::move(generates)), generates(std::move(generates)),
...@@ -939,6 +941,7 @@ struct ClassDeclaration : TypeDeclaration { ...@@ -939,6 +941,7 @@ struct ClassDeclaration : TypeDeclaration {
fields(std::move(fields)) {} fields(std::move(fields)) {}
bool is_extern; bool is_extern;
bool generate_print; bool generate_print;
bool generate_verify;
bool transient; bool transient;
base::Optional<TypeExpression*> super; base::Optional<TypeExpression*> super;
base::Optional<std::string> generates; base::Optional<std::string> generates;
......
...@@ -2965,6 +2965,179 @@ void ImplementationVisitor::GeneratePrintDefinitions(std::string& file_name) { ...@@ -2965,6 +2965,179 @@ void ImplementationVisitor::GeneratePrintDefinitions(std::string& file_name) {
ReplaceFileContentsIfDifferent(file_name, new_contents); ReplaceFileContentsIfDifferent(file_name, new_contents);
} }
namespace {
void GenerateClassFieldVerifier(const std::string& class_name,
const ClassType& class_type, const Field& f,
std::ostream& h_contents,
std::ostream& cc_contents) {
if (!f.generate_verify) return;
const Type* field_type = f.name_and_type.type;
// We only verify tagged types, not raw numbers or pointers.
if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) return;
if (f.index) {
if ((*f.index)->name_and_type.type != TypeOracle::GetSmiType()) {
ReportError("Non-SMI values are not (yet) supported as indexes.");
}
// We already verified the index field because it was listed earlier, so we
// can assume it's safe to read here.
cc_contents << " for (int i = 0; i < Smi::ToInt(READ_FIELD(o, "
<< class_name << "::k"
<< CamelifyString((*f.index)->name_and_type.name)
<< "Offset)); ++i) {\n";
} else {
cc_contents << " {\n";
}
const char* object_type = f.is_weak ? "MaybeObject" : "Object";
const char* read_fn = f.is_weak ? "READ_WEAK_FIELD" : "READ_FIELD";
const char* verify_fn =
f.is_weak ? "VerifyMaybeObjectPointer" : "VerifyPointer";
const char* index_offset = f.index ? " + i * kTaggedSize" : "";
// Name the local var based on the field name for nicer CHECK output.
const std::string value = f.name_and_type.name + "_value";
// Read the field.
cc_contents << " " << object_type << " " << value << " = " << read_fn
<< "(o, " << class_name << "::k"
<< CamelifyString(f.name_and_type.name) << "Offset"
<< index_offset << ");\n";
// Call VerifyPointer or VerifyMaybeObjectPointer on it.
cc_contents << " " << object_type << "::" << verify_fn << "(isolate, "
<< value << ");\n";
// Check that the value is of an appropriate type. We can skip this part for
// 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 = f.is_weak ? value + ".IsWeakOrCleared()" : "";
std::string strong_value =
value + (f.is_weak ? ".GetHeapObjectOrSmi()" : "");
for (const std::string& runtime_type : field_type->GetRuntimeTypes()) {
if (!type_check.empty()) type_check += " || ";
type_check += strong_value + ".Is" + runtime_type + "()";
}
// Many subtypes of JSObject can be verified in partially-initialized states
// where their fields are all undefined. We explicitly allow that here. For
// any such fields that should never be undefined, we can include extra code
// in the custom verifier functions for them.
// TODO(1240798): If Factory::InitializeJSObjectFromMap is updated to use
// correct initial values based on the type of the field, then make this
// check stricter too.
if (class_type.IsSubtypeOf(TypeOracle::GetJSObjectType())) {
type_check += " || " + strong_value + ".IsUndefined(isolate)";
}
cc_contents << " CHECK(" << type_check << ");\n";
}
cc_contents << " }\n";
}
} // namespace
void ImplementationVisitor::GenerateClassVerifiers(
const std::string& output_directory) {
const char* file_name = "class-verifiers-from-dsl";
std::stringstream h_contents;
std::stringstream cc_contents;
h_contents << "#ifndef V8_CLASS_VERIFIERS_FROM_DSL_H_\n"
"#define V8_CLASS_VERIFIERS_FROM_DSL_H_\n"
"\n";
const char* enabled_check = "\n#ifdef VERIFY_HEAP\n";
h_contents << enabled_check;
cc_contents << enabled_check;
h_contents << "\n#include \"src/objects.h\"\n";
for (const std::string& include_path : GlobalContext::CppIncludes()) {
cc_contents << "#include " << StringLiteralQuote(include_path) << "\n";
}
cc_contents << "#include \"torque-generated/" << file_name << ".h\"\n";
cc_contents
<< "\n// Has to be the last include (doesn't have include guards):\n"
"#include \"src/objects/object-macros.h\"\n";
const char* namespaces =
"\nnamespace v8 {\n"
"namespace internal {\n"
"\n";
h_contents << namespaces;
cc_contents << namespaces;
const char* verifier_class = "ClassVerifiersFromDSL";
h_contents << "class " << verifier_class << "{\n";
h_contents << " public:\n";
for (auto i : GlobalContext::GetClasses()) {
ClassType* type = i.second;
if (!type->IsExtern() || !type->ShouldGenerateVerify()) continue;
std::string method_name = i.first + "Verify";
h_contents << " static void " << method_name << "(" << i.first
<< " o, Isolate* isolate);\n";
cc_contents << "void " << verifier_class << "::" << method_name << "("
<< i.first << " o, Isolate* isolate) {\n";
// First, do any verification for the super class. Not all classes have
// verifiers, so skip to the nearest super class that has one.
const ClassType* super_type = type->GetSuperClass();
while (super_type && !super_type->ShouldGenerateVerify()) {
super_type = super_type->GetSuperClass();
}
if (super_type) {
std::string super_name = super_type->name();
if (super_name == "HeapObject") {
// Special case: HeapObjectVerify checks the Map type and dispatches to
// more specific types, so calling it here would cause infinite
// recursion. We could consider moving that behavior into a different
// method to make the contract of *Verify methods more consistent, but
// for now we'll just avoid the bad case.
cc_contents << " " << super_name << "Verify(o, isolate);\n";
} else {
cc_contents << " o->" << super_name << "Verify(isolate);\n";
}
}
// Second, verify that this object is what it claims to be.
cc_contents << " CHECK(o.Is" << i.first << "());\n";
// Third, verify its properties.
for (auto f : type->fields()) {
GenerateClassFieldVerifier(i.first, *i.second, f, h_contents,
cc_contents);
}
cc_contents << "}\n";
}
h_contents << "};\n";
const char* end_namespaces =
"\n} // namespace internal\n"
"} // namespace v8\n";
h_contents << end_namespaces;
cc_contents << end_namespaces;
cc_contents << "\n#include \"src/objects/object-macros-undef.h\"\n";
const char* end_enabled_check = "\n#endif // VERIFY_HEAP\n";
h_contents << end_enabled_check;
cc_contents << end_enabled_check;
h_contents << "\n#endif // V8_CLASS_VERIFIERS_FROM_DSL_H_\n";
ReplaceFileContentsIfDifferent(output_directory + "/" + file_name + ".h",
h_contents.str());
ReplaceFileContentsIfDifferent(output_directory + "/" + file_name + ".cc",
cc_contents.str());
}
} // namespace torque } // namespace torque
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -278,6 +278,7 @@ class ImplementationVisitor { ...@@ -278,6 +278,7 @@ class ImplementationVisitor {
void GenerateBuiltinDefinitions(std::string& file_name); void GenerateBuiltinDefinitions(std::string& file_name);
void GenerateClassDefinitions(std::string& file_name); void GenerateClassDefinitions(std::string& file_name);
void GeneratePrintDefinitions(std::string& file_name); void GeneratePrintDefinitions(std::string& file_name);
void GenerateClassVerifiers(const std::string& output_directory);
VisitResult Visit(Expression* expr); VisitResult Visit(Expression* expr);
const Type* Visit(Statement* stmt); const Type* Visit(Statement* stmt);
......
...@@ -88,6 +88,8 @@ void CompileCurrentAst(TorqueCompilerOptions options) { ...@@ -88,6 +88,8 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
output_directory + "/objects-printer-from-dsl.cc"; output_directory + "/objects-printer-from-dsl.cc";
implementation_visitor.GeneratePrintDefinitions(output_source_path); implementation_visitor.GeneratePrintDefinitions(output_source_path);
implementation_visitor.GenerateClassVerifiers(output_directory);
for (Namespace* n : GlobalContext::Get().GetNamespaces()) { for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
implementation_visitor.EndNamespaceFile(n); implementation_visitor.EndNamespaceFile(n);
implementation_visitor.GenerateImplementation(output_directory, n); implementation_visitor.GenerateImplementation(output_directory, n);
......
...@@ -656,8 +656,9 @@ class AnnotationSet { ...@@ -656,8 +656,9 @@ class AnnotationSet {
base::Optional<ParseResult> MakeClassDeclaration( base::Optional<ParseResult> MakeClassDeclaration(
ParseResultIterator* child_results) { ParseResultIterator* child_results) {
AnnotationSet annotations(child_results, {"@generatePrint"}); AnnotationSet annotations(child_results, {"@generatePrint", "@noVerifier"});
bool generate_print = annotations.Contains("@generatePrint"); bool generate_print = annotations.Contains("@generatePrint");
bool generate_verify = !annotations.Contains("@noVerifier");
auto is_extern = child_results->NextAs<bool>(); auto is_extern = child_results->NextAs<bool>();
auto transient = child_results->NextAs<bool>(); auto transient = child_results->NextAs<bool>();
auto name = child_results->NextAs<Identifier*>(); auto name = child_results->NextAs<Identifier*>();
...@@ -681,8 +682,8 @@ base::Optional<ParseResult> MakeClassDeclaration( ...@@ -681,8 +682,8 @@ base::Optional<ParseResult> MakeClassDeclaration(
}); });
Declaration* result = MakeNode<ClassDeclaration>( Declaration* result = MakeNode<ClassDeclaration>(
name, is_extern, generate_print, transient, std::move(extends), name, is_extern, generate_print, generate_verify, transient,
std::move(generates), std::move(methods), fields); std::move(extends), std::move(generates), std::move(methods), fields);
return ParseResult{result}; return ParseResult{result};
} }
...@@ -1258,13 +1259,19 @@ base::Optional<ParseResult> MakeNameAndExpressionFromExpression( ...@@ -1258,13 +1259,19 @@ base::Optional<ParseResult> MakeNameAndExpressionFromExpression(
base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) { base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
auto conditional = child_results->NextAs<base::Optional<std::string>>(); auto conditional = child_results->NextAs<base::Optional<std::string>>();
AnnotationSet annotations(child_results, {"@noVerifier"});
bool generate_verify = !annotations.Contains("@noVerifier");
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<std::string>>();
auto type = child_results->NextAs<TypeExpression*>(); auto type = child_results->NextAs<TypeExpression*>();
return ParseResult{ClassFieldExpression{ return ParseResult{ClassFieldExpression{{name, type},
{name, type}, index, conditional, weak, const_qualified}}; index,
conditional,
weak,
const_qualified,
generate_verify}};
} }
base::Optional<ParseResult> MakeStructField( base::Optional<ParseResult> MakeStructField(
...@@ -1484,7 +1491,7 @@ struct TorqueGrammar : Grammar { ...@@ -1484,7 +1491,7 @@ struct TorqueGrammar : Grammar {
Symbol classField = {Rule( Symbol classField = {Rule(
{Optional<std::string>( {Optional<std::string>(
Sequence({Token("@ifdef"), Token("("), &identifier, Token(")")})), Sequence({Token("@ifdef"), Token("("), &identifier, Token(")")})),
CheckIf(Token("weak")), CheckIf(Token("const")), &name, annotations, CheckIf(Token("weak")), CheckIf(Token("const")), &name,
optionalArraySpecifier, Token(":"), &type, Token(";")}, optionalArraySpecifier, Token(":"), &type, Token(";")},
MakeClassField)}; MakeClassField)};
......
...@@ -35,12 +35,13 @@ class TypeOracle : public ContextualClass<TypeOracle> { ...@@ -35,12 +35,13 @@ class TypeOracle : public ContextualClass<TypeOracle> {
static ClassType* GetClassType(const Type* parent, const std::string& name, static ClassType* GetClassType(const Type* parent, const std::string& name,
bool is_extern, bool generate_print, bool is_extern, bool generate_print,
bool transient, const std::string& generates, bool generate_verify, bool transient,
const std::string& generates,
ClassDeclaration* decl, ClassDeclaration* decl,
const TypeAlias* alias) { const TypeAlias* alias) {
ClassType* result = ClassType* result = new ClassType(
new ClassType(parent, CurrentNamespace(), name, is_extern, parent, CurrentNamespace(), name, is_extern, generate_print,
generate_print, transient, generates, decl, alias); generate_verify, transient, generates, decl, alias);
Get().struct_types_.push_back(std::unique_ptr<ClassType>(result)); Get().struct_types_.push_back(std::unique_ptr<ClassType>(result));
return result; return result;
} }
......
...@@ -116,7 +116,8 @@ const StructType* TypeVisitor::ComputeType(StructDeclaration* decl) { ...@@ -116,7 +116,8 @@ const StructType* TypeVisitor::ComputeType(StructDeclaration* decl) {
{field.name_and_type.name->value, field_type}, {field.name_and_type.name->value, field_type},
offset, offset,
false, false,
field.const_qualified}); field.const_qualified,
false});
offset += LoweredSlotCount(field_type); offset += LoweredSlotCount(field_type);
} }
DeclareMethods(struct_type, decl->methods); DeclareMethods(struct_type, decl->methods);
...@@ -151,7 +152,7 @@ const ClassType* TypeVisitor::ComputeType(ClassDeclaration* decl) { ...@@ -151,7 +152,7 @@ const ClassType* TypeVisitor::ComputeType(ClassDeclaration* decl) {
new_class = TypeOracle::GetClassType( new_class = TypeOracle::GetClassType(
super_type, decl->name->value, decl->is_extern, decl->generate_print, super_type, decl->name->value, decl->is_extern, decl->generate_print,
decl->transient, generates, decl, alias); decl->generate_verify, decl->transient, generates, decl, alias);
} else { } else {
if (decl->super) { if (decl->super) {
ReportError("Only extern classes can inherit."); ReportError("Only extern classes can inherit.");
...@@ -161,7 +162,8 @@ const ClassType* TypeVisitor::ComputeType(ClassDeclaration* decl) { ...@@ -161,7 +162,8 @@ const ClassType* TypeVisitor::ComputeType(ClassDeclaration* decl) {
} }
new_class = TypeOracle::GetClassType( new_class = TypeOracle::GetClassType(
TypeOracle::GetTaggedType(), decl->name->value, decl->is_extern, TypeOracle::GetTaggedType(), decl->name->value, decl->is_extern,
decl->generate_print, decl->transient, "FixedArray", decl, alias); decl->generate_print, decl->generate_verify, decl->transient,
"FixedArray", decl, alias);
} }
GlobalContext::RegisterClass(decl->name->value, new_class); GlobalContext::RegisterClass(decl->name->value, new_class);
return new_class; return new_class;
...@@ -248,7 +250,8 @@ void TypeVisitor::VisitClassFieldsAndMethods( ...@@ -248,7 +250,8 @@ void TypeVisitor::VisitClassFieldsAndMethods(
{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,
field_expression.const_qualified}); field_expression.const_qualified,
field_expression.generate_verify});
} else { } else {
if (seen_indexed_field) { if (seen_indexed_field) {
ReportError("cannot declare non-indexable field \"", ReportError("cannot declare non-indexable field \"",
...@@ -263,7 +266,8 @@ void TypeVisitor::VisitClassFieldsAndMethods( ...@@ -263,7 +266,8 @@ void TypeVisitor::VisitClassFieldsAndMethods(
{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,
field_expression.const_qualified}); field_expression.const_qualified,
field_expression.generate_verify});
size_t field_size; size_t field_size;
std::string size_string; std::string size_string;
std::string machine_type; std::string machine_type;
......
...@@ -285,20 +285,19 @@ std::vector<Method*> AggregateType::Methods(const std::string& name) const { ...@@ -285,20 +285,19 @@ std::vector<Method*> AggregateType::Methods(const std::string& name) const {
std::string StructType::ToExplicitString() const { std::string StructType::ToExplicitString() const {
std::stringstream result; std::stringstream result;
result << "struct " << name() << "{"; result << "struct " << name();
PrintCommaSeparatedList(result, fields());
result << "}";
return result.str(); return result.str();
} }
ClassType::ClassType(const Type* parent, Namespace* nspace, ClassType::ClassType(const Type* parent, Namespace* nspace,
const std::string& name, bool is_extern, const std::string& name, bool is_extern,
bool generate_print, bool transient, bool generate_print, bool generate_verify, bool transient,
const std::string& generates, const ClassDeclaration* decl, const std::string& generates, const ClassDeclaration* decl,
const TypeAlias* alias) const TypeAlias* alias)
: AggregateType(Kind::kClassType, parent, nspace, name), : AggregateType(Kind::kClassType, parent, nspace, name),
is_extern_(is_extern), is_extern_(is_extern),
generate_print_(generate_print), generate_print_(generate_print),
generate_verify_(generate_verify),
transient_(transient), transient_(transient),
size_(0), size_(0),
has_indexed_field_(false), has_indexed_field_(false),
...@@ -326,9 +325,7 @@ std::string ClassType::GetGeneratedTypeNameImpl() const { ...@@ -326,9 +325,7 @@ std::string ClassType::GetGeneratedTypeNameImpl() const {
std::string ClassType::ToExplicitString() const { std::string ClassType::ToExplicitString() const {
std::stringstream result; std::stringstream result;
result << "class " << name() << "{"; result << "class " << name();
PrintCommaSeparatedList(result, fields());
result << "}";
return result.str(); return result.str();
} }
......
...@@ -103,6 +103,7 @@ class Type : public TypeBase { ...@@ -103,6 +103,7 @@ class Type : public TypeBase {
virtual bool IsTransient() const { return false; } virtual bool IsTransient() const { return false; }
virtual const Type* NonConstexprVersion() const { return this; } virtual const Type* NonConstexprVersion() const { return this; }
base::Optional<const ClassType*> ClassSupertype() const; base::Optional<const ClassType*> ClassSupertype() const;
virtual std::vector<std::string> GetRuntimeTypes() const { return {}; }
static const Type* CommonSupertype(const Type* a, const Type* b); static const Type* CommonSupertype(const Type* a, const Type* b);
void AddAlias(std::string alias) const { aliases_.insert(std::move(alias)); } void AddAlias(std::string alias) const { aliases_.insert(std::move(alias)); }
...@@ -154,6 +155,7 @@ struct Field { ...@@ -154,6 +155,7 @@ struct Field {
size_t offset; size_t offset;
bool is_weak; bool is_weak;
bool const_qualified; bool const_qualified;
bool generate_verify;
}; };
std::ostream& operator<<(std::ostream& os, const Field& name_and_type); std::ostream& operator<<(std::ostream& os, const Field& name_and_type);
...@@ -210,6 +212,7 @@ class AbstractType final : public Type { ...@@ -210,6 +212,7 @@ class AbstractType final : public Type {
if (non_constexpr_version_) return non_constexpr_version_; if (non_constexpr_version_) return non_constexpr_version_;
return this; return this;
} }
std::vector<std::string> GetRuntimeTypes() const override { return {name()}; }
private: private:
friend class TypeOracle; friend class TypeOracle;
...@@ -397,6 +400,15 @@ class UnionType final : public Type { ...@@ -397,6 +400,15 @@ class UnionType final : public Type {
return union_type ? UnionType(*union_type) : UnionType(t); return union_type ? UnionType(*union_type) : UnionType(t);
} }
std::vector<std::string> GetRuntimeTypes() const override {
std::vector<std::string> result;
for (const Type* member : types_) {
std::vector<std::string> sub_result = member->GetRuntimeTypes();
result.insert(result.end(), sub_result.begin(), sub_result.end());
}
return result;
}
private: private:
explicit UnionType(const Type* t) : Type(Kind::kUnionType, t), types_({t}) {} explicit UnionType(const Type* t) : Type(Kind::kUnionType, t), types_({t}) {}
void RecomputeParent(); void RecomputeParent();
...@@ -444,6 +456,7 @@ class AggregateType : public Type { ...@@ -444,6 +456,7 @@ class AggregateType : public Type {
std::vector<Method*> Methods(const std::string& name) const; std::vector<Method*> Methods(const std::string& name) const;
std::vector<const AggregateType*> GetHierarchy() const; std::vector<const AggregateType*> GetHierarchy() const;
std::vector<std::string> GetRuntimeTypes() const override { return {name_}; }
protected: protected:
AggregateType(Kind kind, const Type* parent, Namespace* nspace, AggregateType(Kind kind, const Type* parent, Namespace* nspace,
...@@ -496,6 +509,7 @@ class ClassType final : public AggregateType { ...@@ -496,6 +509,7 @@ class ClassType final : public AggregateType {
std::string GetGeneratedTNodeTypeNameImpl() const override; std::string GetGeneratedTNodeTypeNameImpl() const override;
bool IsExtern() const { return is_extern_; } bool IsExtern() const { return is_extern_; }
bool ShouldGeneratePrint() const { return generate_print_; } bool ShouldGeneratePrint() const { return generate_print_; }
bool ShouldGenerateVerify() const { return generate_verify_; }
bool IsTransient() const override { return transient_; } bool IsTransient() const override { return transient_; }
bool HasIndexedField() const override; bool HasIndexedField() const override;
size_t size() const { return size_; } size_t size() const { return size_; }
...@@ -518,12 +532,13 @@ class ClassType final : public AggregateType { ...@@ -518,12 +532,13 @@ class ClassType final : public AggregateType {
friend class TypeOracle; friend class TypeOracle;
friend class TypeVisitor; friend class TypeVisitor;
ClassType(const Type* parent, Namespace* nspace, const std::string& name, ClassType(const Type* parent, Namespace* nspace, const std::string& name,
bool is_extern, bool generate_print, bool transient, bool is_extern, bool generate_print, bool generate_verify,
const std::string& generates, const ClassDeclaration* decl, bool transient, const std::string& generates,
const TypeAlias* alias); const ClassDeclaration* decl, const TypeAlias* alias);
bool is_extern_; bool is_extern_;
bool generate_print_; bool generate_print_;
bool generate_verify_;
bool transient_; bool transient_;
size_t size_; size_t size_;
mutable bool has_indexed_field_; mutable bool has_indexed_field_;
......
...@@ -770,6 +770,7 @@ namespace test { ...@@ -770,6 +770,7 @@ namespace test {
assert(a.b.GetX() == 2); assert(a.b.GetX() == 2);
} }
@noVerifier
extern class TestClassWithAllTypes extends JSObject { extern class TestClassWithAllTypes extends JSObject {
a: int8; a: int8;
b: uint8; b: uint8;
...@@ -786,6 +787,7 @@ namespace test { ...@@ -786,6 +787,7 @@ namespace test {
// This class should throw alignment errors if @ifdef decorators aren't // This class should throw alignment errors if @ifdef decorators aren't
// working. // working.
@noVerifier
extern class PreprocessingTest extends JSObject { extern class PreprocessingTest extends JSObject {
@ifdef(FALSE_FOR_TESTING) a: int8; @ifdef(FALSE_FOR_TESTING) a: int8;
@ifdef(TRUE_FOR_TESTING) a: int16; @ifdef(TRUE_FOR_TESTING) a: int16;
...@@ -894,8 +896,12 @@ namespace test { ...@@ -894,8 +896,12 @@ namespace test {
type Baztype = Foo | FooType; type Baztype = Foo | FooType;
extern class Foo extends JSObject { fooField: FooType; } @noVerifier
extern class Foo extends JSObject {
fooField: FooType;
}
@noVerifier
extern class Bar extends Foo { extern class Bar extends Foo {
barField: Bartype; barField: Bartype;
bazfield: Baztype; bazfield: Baztype;
......
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