Files
swift-mirror/unittests/Syntax/ThreadSafeCachingTests.cpp
David Farler c343298b8f [Syntax] Implement return-statement and integer-literal-expr
A return statement needs something to return, so implement
integer-literal-expression too. This necessarily also forced
UnknownExprSyntax, UnknownStmtSyntax, and UnknownDeclSyntax,
which are stand-in token buckets for when we don't know
how to transform/migrate an AST.

This commit also contains the core function for caching
SyntaxData children. This is highly tricky code, with some
detailed comments in SyntaxData.{h,cpp}. The gist is that
we have to atomically swap in a SyntaxData pointer into the
child field, so we can maintain pointer identity of SyntaxData
nodes, while still being able to cache them internally.

To prove that this works, there is a multithreaded test that
checks that two threads can ask for a child that hasn't been
cached yet without crashing or violating pointer identity.

https://bugs.swift.org/browse/SR-4010
2017-02-22 18:45:29 -08:00

55 lines
1.8 KiB
C++

#include "swift/Syntax/ExprSyntax.h"
#include "swift/Syntax/SyntaxFactory.h"
#include "swift/Syntax/StmtSyntax.h"
#include "llvm/ADT/SmallString.h"
#include "gtest/gtest.h"
#include <thread>
using namespace swift;
using namespace swift::syntax;
static void getExpressionFrom(ReturnStmtSyntax Return,
uintptr_t *DataPointer) {
auto Expression = Return.getExpression().getValue();
auto Data = Expression.getDataPointer();
*DataPointer = reinterpret_cast<uintptr_t>(Data);
}
// Tests that, when multiple threads ask for a child node of the same syntax
// node:
// - Only one thread inserts the realized child into the parent
// - Both threads get the exact same child (by identity)
TEST(ThreadSafeCachingTests, ReturnGetExpression) {
auto ReturnKW = SyntaxFactory::makeReturnKeyword({}, Trivia::spaces(1));
auto Minus = SyntaxFactory::makePrefixOpereator("-", {});
auto One = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
auto MinusOne = SyntaxFactory::makeIntegerLiteralExpr(Minus, One);
for (unsigned i = 0; i < 10000; ++i) {
llvm::SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne);
uintptr_t FirstDataPointer;
uintptr_t SecondDataPointer;
std::thread first(getExpressionFrom, Return, &FirstDataPointer);
std::thread second(getExpressionFrom, Return, &SecondDataPointer);
first.join();
second.join();
auto DataPointer = reinterpret_cast<uintptr_t>(
Return.getExpression().getValue().getDataPointer());
ASSERT_EQ(FirstDataPointer, SecondDataPointer);
ASSERT_EQ(FirstDataPointer, DataPointer);
if (FirstDataPointer != SecondDataPointer ||
FirstDataPointer != DataPointer) {
break;
}
}
}