/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #define ANNOTATE(property) __attribute__((annotate(property))) extern void GC() ANNOTATE("GC Call"); void GC() { // If the implementation is too trivial, the function body won't be emitted at // all. asm(""); } // Special-cased function -- code that can run JS has an artificial edge to // js::RunScript. namespace js { void RunScript() { GC(); } } // namespace js struct Cell { int f; } ANNOTATE("GC Thing"); extern void foo(); void bar() { GC(); } typedef void (*func_t)(); class Base { public: int ANNOTATE("field annotation") dummy; virtual void someGC() ANNOTATE("Base pure virtual method") = 0; virtual void someGC(int) ANNOTATE("overloaded Base pure virtual method") = 0; virtual void sibGC() = 0; virtual void onBase() { bar(); } func_t functionField; // For now, this is just to verify that the plugin doesn't crash. The // analysis code does not yet look at this annotation or output it anywhere // (though it *is* being recorded.) static float testAnnotations() ANNOTATE("static func"); // Similar, though sixgill currently completely ignores parameter annotations. static double testParamAnnotations(Cell& ANNOTATE("param annotation") ANNOTATE("second param annot") cell) ANNOTATE("static func") ANNOTATE("second func"); }; float Base::testAnnotations() { asm(""); return 1.1; } double Base::testParamAnnotations(Cell& cell) { asm(""); return 1.2; } class Super : public Base { public: virtual void ANNOTATE("Super pure virtual") noneGC() = 0; virtual void allGC() = 0; virtual void onSuper() { asm(""); } void nonVirtualFunc() { asm(""); } }; class Sub1 : public Super { public: void noneGC() override { foo(); } void someGC() override ANNOTATE("Sub1 override") ANNOTATE("second attr") { foo(); } void someGC(int) override ANNOTATE("Sub1 override for int overload") { foo(); } void allGC() override { foo(); bar(); } void sibGC() override { foo(); } void onBase() override { foo(); } } ANNOTATE("CSU1") ANNOTATE("CSU2"); class Sub2 : public Super { public: void noneGC() override { foo(); } void someGC() override { foo(); bar(); } void someGC(int) override { foo(); bar(); } void allGC() override { foo(); bar(); } void sibGC() override { foo(); } }; class Sibling : public Base { public: virtual void noneGC() { foo(); } void someGC() override { foo(); bar(); } void someGC(int) override { foo(); bar(); } virtual void allGC() { foo(); bar(); } void sibGC() override { bar(); } }; class AutoSuppressGC { public: AutoSuppressGC() {} ~AutoSuppressGC() {} } ANNOTATE("Suppress GC"); void use(Cell*) { asm(""); } class nsISupports { public: virtual ANNOTATE("Can run script") void danger() { asm(""); } virtual ~nsISupports() = 0; }; class nsIPrincipal : public nsISupports { public: ~nsIPrincipal() override{}; }; struct JSPrincipals { int debugToken; JSPrincipals() = default; virtual ~JSPrincipals() { GC(); } }; class nsJSPrincipals : public nsIPrincipal, public JSPrincipals { public: void Release() { delete this; } }; class SafePrincipals : public nsIPrincipal { public: ~SafePrincipals() { foo(); } }; void f() { Sub1 s1; Sub2 s2; static Cell cell; { Cell* c1 = &cell; s1.noneGC(); use(c1); } { Cell* c2 = &cell; s2.someGC(); use(c2); } { Cell* c3 = &cell; s1.allGC(); use(c3); } { Cell* c4 = &cell; s2.noneGC(); use(c4); } { Cell* c5 = &cell; s2.someGC(); use(c5); } { Cell* c6 = &cell; s2.allGC(); use(c6); } Super* super = &s2; { Cell* c7 = &cell; super->noneGC(); use(c7); } { Cell* c8 = &cell; super->someGC(); use(c8); } { Cell* c9 = &cell; super->allGC(); use(c9); } { Cell* c10 = &cell; s1.functionField(); use(c10); } { Cell* c11 = &cell; super->functionField(); use(c11); } { Cell* c12 = &cell; super->sibGC(); use(c12); } Base* base = &s2; { Cell* c13 = &cell; base->sibGC(); use(c13); } nsJSPrincipals pals; { Cell* c14 = &cell; nsISupports* p = &pals; p->danger(); use(c14); } // Base defines, Sub1 overrides, static Super can call either. { Cell* c15 = &cell; super->onBase(); use(c15); } { Cell* c16 = &cell; s2.someGC(7); use(c16); } { Cell* c17 = &cell; super->someGC(7); use(c17); } { nsJSPrincipals* princ = new nsJSPrincipals(); Cell* c18 = &cell; delete princ; // Can GC use(c18); } { nsJSPrincipals* princ = new nsJSPrincipals(); nsISupports* supp = static_cast(princ); Cell* c19 = &cell; delete supp; // Can GC use(c19); } { auto* safe = new SafePrincipals(); Cell* c20 = &cell; delete safe; // Cannot GC use(c20); } { auto* safe = new SafePrincipals(); nsISupports* supp = static_cast(safe); Cell* c21 = &cell; delete supp; // Compiler thinks destructor can GC. use(c21); } }