Reland "[torque] move class tests to unittests"
This is a reland of f589d56101
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}
This commit is contained in:
parent
00be36ec7c
commit
c33a1ef227
@ -155,68 +155,48 @@ void ImplementationVisitor::Visit(NamespaceConstant* decl) {
|
||||
|
||||
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(
|
||||
|
@ -231,7 +231,14 @@ class Stack {
|
||||
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()};
|
||||
|
@ -823,59 +823,6 @@ namespace test {
|
||||
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 @@ namespace test {
|
||||
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);
|
||||
|
@ -13,17 +13,83 @@ namespace torque {
|
||||
|
||||
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 @@ TEST(Torque, StackDeleteRange) {
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user