Reland^2 "[torque] move class tests to unittests"
This is a reland of c33a1ef227bba6d7b442170fcee8ba01c45316d6
It seems the revert was based on a flake.
Original change's description:
> Reland "[torque] move class tests to unittests"
>
> This is a reland of f589d56101783d915f8350fd64dc89c9557022e6
>
> Now with an ASAN-container-overflow false positive workaround:
> Somehow ASAN was unhappy about a simple
> std::vector<std::string>::push_back.
> Increasing the std::vector capacity before doing the push_back
> strangely fixes the problem.
>
> Original change's description:
> > [torque] move class tests to unittests
> >
> > This avoids the generation of fake external classes.
> >
> > Bug: v8:7793
> > Change-Id: I9744b299d3ec474d72b298b4f6143f95e345d1d9
> > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1625991
> > Reviewed-by: Simon Zünd <szuend@chromium.org>
> > Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> > Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#61778}
>
> TBR: szuend@chromium.org, sigurds@chromium.org
> Bug: v8:7793
> Change-Id: Ifa1958e4d6e850ba27632aa95c7efaf5ca4bfefa
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1627970
> Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#61807}
Bug: v8:7793
Change-Id: Ia403f1b784500c0903172f13e74c0b325e82599f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1627980
Reviewed-by: Simon Zünd <szuend@chromium.org>
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61819}
diff --git a/src/torque/implementation-visitor.cc b/src/torque/implementation-visitor.cc
index 56adb21..8b139ad 100644
--- a/src/torque/implementation-visitor.cc
+++ b/src/torque/implementation-visitor.cc
@@ -155,68 +155,48 @@
void ImplementationVisitor::Visit(TypeAlias* alias) {
if (alias->IsRedeclaration()) return;
- const ClassType* class_type = ClassType::DynamicCast(alias->type());
- if (class_type && class_type->IsExtern()) {
- // Classes that are in the default namespace are defined in the C++
- // world and all of their fields and methods are declared explicitly.
- // Internal classes (e.g. ones used for testing that are not in the default
- // name space) need to be defined by Torque.
- // TODO(danno): This is a pretty cheesy hack for now. There should be a more
- // robust mechanism for this, e.g. declaring classes 'extern' or something.
- if (class_type->nspace()->IsTestNamespace()) {
- const ClassType* super = class_type->GetSuperClass();
- std::string class_name{super->GetGeneratedTNodeTypeName()};
- header_out() << " class " << class_type->name() << " : public "
- << class_name << " {\n";
- header_out() << " public:\n";
- header_out() << " DEFINE_FIELD_OFFSET_CONSTANTS(" << class_name
- << "::";
- header_out() << (super->IsAbstract() ? "kHeaderSize" : "kSize");
- header_out() << ", TORQUE_GENERATED_"
- << CapifyStringWithUnderscores(class_type->name())
- << "_FIELDS)\n";
- header_out() << " };\n";
- } else if (!class_type->nspace()->IsDefaultNamespace()) {
- ReportError(
- "extern classes are currently only supported in the default and test "
- "namespaces");
+ if (const ClassType* class_type = ClassType::DynamicCast(alias->type())) {
+ if (class_type->IsExtern() && !class_type->nspace()->IsDefaultNamespace()) {
+ Error(
+ "extern classes are currently only supported in the default "
+ "namespace");
}
- return;
- }
- const StructType* struct_type = StructType::DynamicCast(alias->type());
- if (!struct_type) return;
- const std::string& name = struct_type->name();
- header_out() << " struct " << name << " {\n";
- for (auto& field : struct_type->fields()) {
- header_out() << " " << field.name_and_type.type->GetGeneratedTypeName();
- header_out() << " " << field.name_and_type.name << ";\n";
- }
- header_out() << "\n std::tuple<";
- bool first = true;
- for (const Type* type : LowerType(struct_type)) {
- if (!first) {
- header_out() << ", ";
+ } else if (const StructType* struct_type =
+ StructType::DynamicCast(alias->type())) {
+ const std::string& name = struct_type->name();
+ header_out() << " struct " << name << " {\n";
+ for (auto& field : struct_type->fields()) {
+ header_out() << " "
+ << field.name_and_type.type->GetGeneratedTypeName();
+ header_out() << " " << field.name_and_type.name << ";\n";
}
- first = false;
- header_out() << type->GetGeneratedTypeName();
- }
- header_out() << "> Flatten() const {\n"
- << " return std::tuple_cat(";
- first = true;
- for (auto& field : struct_type->fields()) {
- if (!first) {
- header_out() << ", ";
+ header_out() << "\n std::tuple<";
+ bool first = true;
+ for (const Type* type : LowerType(struct_type)) {
+ if (!first) {
+ header_out() << ", ";
+ }
+ first = false;
+ header_out() << type->GetGeneratedTypeName();
}
- first = false;
- if (field.name_and_type.type->IsStructType()) {
- header_out() << field.name_and_type.name << ".Flatten()";
- } else {
- header_out() << "std::make_tuple(" << field.name_and_type.name << ")";
+ header_out() << "> Flatten() const {\n"
+ << " return std::tuple_cat(";
+ first = true;
+ for (auto& field : struct_type->fields()) {
+ if (!first) {
+ header_out() << ", ";
+ }
+ first = false;
+ if (field.name_and_type.type->IsStructType()) {
+ header_out() << field.name_and_type.name << ".Flatten()";
+ } else {
+ header_out() << "std::make_tuple(" << field.name_and_type.name << ")";
+ }
}
+ header_out() << ");\n";
+ header_out() << " }\n";
+ header_out() << " };\n";
}
- header_out() << ");\n";
- header_out() << " }\n";
- header_out() << " };\n";
}
VisitResult ImplementationVisitor::InlineMacro(
diff --git a/src/torque/utils.h b/src/torque/utils.h
index 8f02b0a..dc9a775 100644
--- a/src/torque/utils.h
+++ b/src/torque/utils.h
@@ -231,7 +231,14 @@
void Poke(BottomOffset from_bottom, T x) {
elements_.at(from_bottom.offset) = std::move(x);
}
- void Push(T x) { elements_.push_back(std::move(x)); }
+ void Push(T x) {
+ // Manually increasing the std::vector capacity is a workaround for an
+ // ASAN-container-overflow false positive.
+ if (elements_.size() == elements_.capacity()) {
+ elements_.reserve(2 * elements_.size() + 1);
+ }
+ elements_.push_back(std::move(x));
+ }
StackRange TopRange(size_t slot_count) const {
DCHECK_GE(Size(), slot_count);
return StackRange{AboveTop() - slot_count, AboveTop()};
diff --git a/test/torque/test-torque.tq b/test/torque/test-torque.tq
index e07baec..d165fd5 100644
--- a/test/torque/test-torque.tq
+++ b/test/torque/test-torque.tq
@@ -823,59 +823,6 @@
assert(a.b.GetX() == 2);
}
- @noVerifier
- extern class TestClassWithAllTypes extends JSObject {
- a: int8;
- b: uint8;
- b2: uint8;
- b3: uint8;
- c: int16;
- d: uint16;
- e: int32;
- f: uint32;
- g: RawPtr;
- h: intptr;
- i: uintptr;
- }
-
- // This class should throw alignment errors if @if decorators aren't
- // working.
- @noVerifier
- extern class PreprocessingTest extends JSObject {
- @if(FALSE_FOR_TESTING) a: int8;
- @if(TRUE_FOR_TESTING) a: int16;
- b: int16;
- d: int32;
- @ifnot(TRUE_FOR_TESTING) e: int8;
- @ifnot(FALSE_FOR_TESTING) f: int16;
- g: int16;
- h: int32;
- }
-
- @export
- macro TestClassWithAllTypesLoadsAndStores(
- t: TestClassWithAllTypes, r: RawPtr, v1: int8, v2: uint8, v3: int16,
- v4: uint16) {
- t.a = v1;
- t.b = v2;
- t.c = v3;
- t.d = v4;
- t.e = 0;
- t.f = 0;
- t.g = r;
- t.h = 0;
- t.i = 0;
- t.a = t.a;
- t.b = t.b;
- t.c = t.c;
- t.d = t.d;
- t.e = t.e;
- t.f = t.f;
- t.g = t.g;
- t.h = t.h;
- t.i = t.i;
- }
-
class InternalClass {
Flip() labels NotASmi {
const tmp = Cast<Smi>(this.b) otherwise NotASmi;
@@ -956,24 +903,6 @@
check(array.b == 9);
}
- type Baztype = Foo | FooType;
-
- @abstract
- @noVerifier
- extern class Foo extends JSObject {
- fooField: FooType;
- }
-
- @noVerifier
- extern class Bar extends Foo {
- barField: Bartype;
- bazfield: Baztype;
- }
-
- type Bartype = FooType;
-
- type FooType = Smi | Bar;
-
@export
macro TestStaticAssert() {
StaticAssert(1 + 2 == 3);
diff --git a/test/unittests/torque/torque-unittest.cc b/test/unittests/torque/torque-unittest.cc
index 0a912bf..8ad277e 100644
--- a/test/unittests/torque/torque-unittest.cc
+++ b/test/unittests/torque/torque-unittest.cc
@@ -13,17 +13,83 @@
namespace {
-TorqueCompilerResult TestCompileTorque(const std::string& source) {
+// This is a simplified version of the basic Torque type definitions.
+// Some class types are replaced by abstact types to keep it self-contained and
+// small.
+constexpr const char* kTestTorquePrelude = R"(
+type void;
+type never;
+
+type Tagged generates 'TNode<Object>' constexpr 'ObjectPtr';
+type Smi extends Tagged generates 'TNode<Smi>' constexpr 'Smi';
+
+@abstract
+extern class HeapObject extends Tagged {
+ map: Map;
+}
+type Map extends HeapObject generates 'TNode<Map>';
+type Object = Smi | HeapObject;
+type JSReceiver extends HeapObject generates 'TNode<JSReceiver>';
+type JSObject extends JSReceiver generates 'TNode<JSObject>';
+type int32 generates 'TNode<Int32T>' constexpr 'int32_t';
+type uint32 generates 'TNode<Uint32T>' constexpr 'uint32_t';
+type int31 extends int32
+ generates 'TNode<Int32T>' constexpr 'int31_t';
+type uint31 extends uint32
+ generates 'TNode<Uint32T>' constexpr 'uint31_t';
+type int16 extends int31
+ generates 'TNode<Int16T>' constexpr 'int16_t';
+type uint16 extends uint31
+ generates 'TNode<Uint16T>' constexpr 'uint16_t';
+type int8 extends int16 generates 'TNode<Int8T>' constexpr 'int8_t';
+type uint8 extends uint16
+ generates 'TNode<Uint8T>' constexpr 'uint8_t';
+type int64 generates 'TNode<Int64T>' constexpr 'int64_t';
+type intptr generates 'TNode<IntPtrT>' constexpr 'intptr_t';
+type uintptr generates 'TNode<UintPtrT>' constexpr 'uintptr_t';
+type float32 generates 'TNode<Float32T>' constexpr 'float';
+type float64 generates 'TNode<Float64T>' constexpr 'double';
+type bool generates 'TNode<BoolT>' constexpr 'bool';
+type bint generates 'TNode<BInt>' constexpr 'BInt';
+type string constexpr 'const char*';
+type RawPtr generates 'TNode<RawPtrT>' constexpr 'void*';
+type Code extends HeapObject generates 'TNode<Code>';
+type BuiltinPtr extends Smi generates 'TNode<BuiltinPtr>';
+type Context extends HeapObject generates 'TNode<Context>';
+type NativeContext extends Context;
+)";
+
+TorqueCompilerResult TestCompileTorque(std::string source) {
TorqueCompilerOptions options;
options.output_directory = "";
options.collect_language_server_data = false;
options.force_assert_statements = false;
+ source = kTestTorquePrelude + source;
return CompileTorque(source, options);
}
+void ExpectSuccessfulCompilation(std::string source) {
+ TorqueCompilerResult result = TestCompileTorque(std::move(source));
+ std::vector<std::string> messages;
+ for (const auto& message : result.messages) {
+ messages.push_back(message.message);
+ }
+ EXPECT_EQ(messages, std::vector<std::string>{});
+}
+
+template <class T>
+void ExpectFailingCompilation(
+ std::string source, ::testing::PolymorphicMatcher<T> message_pattern) {
+ TorqueCompilerResult result = TestCompileTorque(std::move(source));
+ ASSERT_FALSE(result.messages.empty());
+ EXPECT_THAT(result.messages[0].message, message_pattern);
+}
+
} // namespace
+TEST(Torque, Prelude) { ExpectSuccessfulCompilation(""); }
+
TEST(Torque, StackDeleteRange) {
Stack<int> stack = {1, 2, 3, 4, 5, 6, 7};
stack.DeleteRange(StackRange{BottomOffset{2}, BottomOffset{4}});
@@ -33,31 +99,112 @@
using ::testing::HasSubstr;
TEST(Torque, TypeNamingConventionLintError) {
- std::string source = R"(
- type void;
- type never;
-
+ ExpectFailingCompilation(R"(
type foo generates 'TNode<Foo>';
- )";
-
- const TorqueCompilerResult result = TestCompileTorque(source);
-
- ASSERT_EQ(result.messages.size(), static_cast<size_t>(1));
- EXPECT_THAT(result.messages[0].message, HasSubstr("\"foo\""));
+ )",
+ HasSubstr("\"foo\""));
}
TEST(Torque, StructNamingConventionLintError) {
- const std::string source = R"(
- type void;
- type never;
-
+ ExpectFailingCompilation(R"(
struct foo {}
- )";
+ )",
+ HasSubstr("\"foo\""));
+}
- const TorqueCompilerResult result = TestCompileTorque(source);
+TEST(Torque, ClassDefinition) {
+ ExpectSuccessfulCompilation(R"(
+ extern class TestClassWithAllTypes extends HeapObject {
+ a: int8;
+ b: uint8;
+ b2: uint8;
+ b3: uint8;
+ c: int16;
+ d: uint16;
+ e: int32;
+ f: uint32;
+ g: RawPtr;
+ h: intptr;
+ i: uintptr;
+ }
- ASSERT_EQ(result.messages.size(), static_cast<size_t>(1));
- EXPECT_THAT(result.messages[0].message, HasSubstr("\"foo\""));
+ macro TestClassWithAllTypesLoadsAndStores(
+ t: TestClassWithAllTypes, r: RawPtr, v1: int8, v2: uint8, v3: int16,
+ v4: uint16, v5: int32, v6: uint32, v7: intptr, v8: uintptr) {
+ t.a = v1;
+ t.b = v2;
+ t.c = v3;
+ t.d = v4;
+ t.e = v5;
+ t.f = v6;
+ t.g = r;
+ t.h = v7;
+ t.i = v8;
+ t.a = t.a;
+ t.b = t.b;
+ t.c = t.c;
+ t.d = t.d;
+ t.e = t.e;
+ t.f = t.f;
+ t.g = t.g;
+ t.h = t.h;
+ t.i = t.i;
+ }
+ )");
+}
+
+TEST(Torque, TypeDeclarationOrder) {
+ ExpectSuccessfulCompilation(R"(
+ type Baztype = Foo | FooType;
+
+ @abstract
+ @noVerifier
+ extern class Foo extends HeapObject {
+ fooField: FooType;
+ }
+
+ @noVerifier
+ extern class Bar extends Foo {
+ barField: Bartype;
+ bazfield: Baztype;
+ }
+
+ type Bartype = FooType;
+
+ type FooType = Smi | Bar;
+ )");
+}
+
+TEST(Torque, ConditionalFields) {
+ // This class should throw alignment errors if @if decorators aren't
+ // working.
+ ExpectSuccessfulCompilation(R"(
+ @noVerifier
+ extern class PreprocessingTest extends HeapObject {
+ @if(FALSE_FOR_TESTING) a: int8;
+ @if(TRUE_FOR_TESTING) a: int16;
+ b: int16;
+ d: int32;
+ @ifnot(TRUE_FOR_TESTING) e: int8;
+ @ifnot(FALSE_FOR_TESTING) f: int16;
+ g: int16;
+ h: int32;
+ }
+ )");
+ ExpectFailingCompilation(R"(
+ @noVerifier
+ extern class PreprocessingTest extends HeapObject {
+ @if(TRUE_FOR_TESTING) a: int8;
+ @if(FALSE_FOR_TESTING) a: int16;
+ b: int16;
+ d: int32;
+ @ifnot(FALSE_FOR_TESTING) e: int8;
+ @ifnot(TRUE_FOR_TESTING) f: int16;
+ g: int16;
+ h: int32;
+ }
+ )",
+ HasSubstr("aligned"));
}
} // namespace torque