#include <utility>
#define ANNOTATE(property) __attribute__((annotate(property)))
struct Cell {
int f;
} ANNOTATE("GC Thing");
template <typename T, typename U>
struct UntypedContainer {
char data[sizeof(T) + sizeof(U)];
} ANNOTATE("moz_inherit_type_annotations_from_template_args");
struct RootedCell {
RootedCell(Cell*) {}
} ANNOTATE("Rooted Pointer");
class AutoSuppressGC_Base {
public:
AutoSuppressGC_Base() {}
~AutoSuppressGC_Base() {}
} ANNOTATE("Suppress GC");
class AutoSuppressGC_Child : public AutoSuppressGC_Base {
public:
AutoSuppressGC_Child() : AutoSuppressGC_Base() {}
};
class AutoSuppressGC {
AutoSuppressGC_Child helpImBeingSuppressed;
public:
AutoSuppressGC() {}
};
extern void GC() ANNOTATE("GC Call");
extern void invisible();
void GC() {
asm("");
invisible();
}
extern void usecell(Cell*);
void suppressedFunction() {
GC(); }
void halfSuppressedFunction() {
GC(); }
void unsuppressedFunction() {
GC(); }
volatile static int x = 3;
volatile static int* xp = &x;
struct GCInDestructor {
~GCInDestructor() {
invisible();
asm("");
*xp = 4;
GC();
}
};
template <typename T>
void usecontainer(T* value) {
if (value) asm("");
}
Cell* f() {
GCInDestructor kaboom;
Cell cell;
Cell* cell1 = &cell;
Cell* cell2 = &cell;
Cell* cell3 = &cell;
Cell* cell4 = &cell;
{
AutoSuppressGC nogc;
suppressedFunction();
halfSuppressedFunction();
}
usecell(cell1);
halfSuppressedFunction();
usecell(cell2);
unsuppressedFunction();
{
AutoSuppressGC nogc;
}
usecell(cell3);
Cell* cell5 = &cell;
usecell(cell5);
{
UntypedContainer<int, Cell*> container1;
usecontainer(&container1);
GC();
usecontainer(&container1);
}
{
UntypedContainer<int, double> container2;
usecontainer(&container2);
GC();
usecontainer(&container2);
}
Cell* cell6 = &cell;
return cell6;
}
Cell* copy_and_gc(Cell* src) {
GC();
return reinterpret_cast<Cell*>(88);
}
void use(Cell* cell) {
static int x = 0;
if (cell) x++;
}
struct CellContainer {
Cell* cell;
CellContainer() { asm(""); }
};
void loopy() {
Cell cell;
Cell* haz1;
for (int i = 0; i < 10; i++) {
haz1 = copy_and_gc(haz1);
}
Cell* haz2 = &cell;
for (int j = 0; j < 10; j++) {
use(haz2);
GC();
haz2 = &cell;
}
Cell* haz3;
for (int k = 0; k < 10; k++) {
GC();
use(haz3);
haz3 = &cell;
}
Cell* haz4 = &cell;
for (int i2 = 0; i2 < 10; i2++) {
GC();
}
use(haz4);
Cell* haz5;
for (int i3 = 0; i3 < 10; i3++) {
haz5 = &cell;
}
GC();
use(haz5);
Cell* haz6;
for (int i4 = 0; i4 < 10; i4++) {
GC();
haz6 = &cell;
}
for (int i5 = 0; i5 < 10; i5++) {
GC();
CellContainer haz7;
use(haz7.cell);
haz7.cell = &cell;
}
CellContainer haz8;
for (int i6 = 0; i6 < 10; i6++) {
GC();
use(haz8.cell);
haz8.cell = &cell;
}
}
namespace mozilla {
template <typename T>
class UniquePtr {
T* val;
public:
UniquePtr() : val(nullptr) { asm(""); }
UniquePtr(T* p) : val(p) {}
UniquePtr(UniquePtr<T>&& u) : val(u.val) { u.val = nullptr; }
~UniquePtr() { use(val); }
T* get() { return val; }
void reset() { val = nullptr; }
} ANNOTATE("moz_inherit_type_annotations_from_template_args");
}
extern void consume(mozilla::UniquePtr<Cell> uptr);
void safevals() {
Cell cell;
Cell* unsafe1 = &cell;
GC();
use(unsafe1);
Cell* safe2 = &cell;
safe2 = nullptr;
GC();
use(safe2);
Cell* unsafe3 = &cell;
if (reinterpret_cast<long>(&cell) & 0x100) {
unsafe3 = nullptr;
}
GC();
use(unsafe3);
Cell* unsafe3b = &cell;
unsafe3b = nullptr;
unsafe3b = &cell;
GC();
use(unsafe3b);
{
mozilla::UniquePtr<Cell> unsafe4(&cell);
GC();
}
{
mozilla::UniquePtr<Cell> safe5(&cell);
safe5.reset();
GC();
}
{
mozilla::UniquePtr<Cell> safe6(&cell);
GC();
safe6.reset();
}
{
mozilla::UniquePtr<Cell> unsafe7(&cell);
GC();
use(unsafe7.get());
unsafe7.reset();
}
{
mozilla::UniquePtr<Cell> safe8;
GC();
}
{
mozilla::UniquePtr<Cell> safe9(&cell);
consume(std::move(safe9));
GC();
}
{
mozilla::UniquePtr<Cell> unsafe10(&cell);
GC();
consume(std::move(unsafe10));
}
}