source.cpp (6747B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #define ANNOTATE(property) __attribute__((annotate(property))) 8 9 extern void GC() ANNOTATE("GC Call"); 10 11 void GC() { 12 // If the implementation is too trivial, the function body won't be emitted at 13 // all. 14 asm(""); 15 } 16 17 // Special-cased function -- code that can run JS has an artificial edge to 18 // js::RunScript. 19 namespace js { 20 void RunScript() { GC(); } 21 } // namespace js 22 23 struct Cell { 24 int f; 25 } ANNOTATE("GC Thing"); 26 27 extern void foo(); 28 29 void bar() { GC(); } 30 31 typedef void (*func_t)(); 32 33 class Base { 34 public: 35 int ANNOTATE("field annotation") dummy; 36 virtual void someGC() ANNOTATE("Base pure virtual method") = 0; 37 virtual void someGC(int) ANNOTATE("overloaded Base pure virtual method") = 0; 38 virtual void sibGC() = 0; 39 virtual void onBase() { bar(); } 40 func_t functionField; 41 42 // For now, this is just to verify that the plugin doesn't crash. The 43 // analysis code does not yet look at this annotation or output it anywhere 44 // (though it *is* being recorded.) 45 static float testAnnotations() ANNOTATE("static func"); 46 47 // Similar, though sixgill currently completely ignores parameter annotations. 48 static double testParamAnnotations(Cell& ANNOTATE("param annotation") 49 ANNOTATE("second param annot") cell) 50 ANNOTATE("static func") ANNOTATE("second func"); 51 }; 52 53 float Base::testAnnotations() { 54 asm(""); 55 return 1.1; 56 } 57 58 double Base::testParamAnnotations(Cell& cell) { 59 asm(""); 60 return 1.2; 61 } 62 63 class Super : public Base { 64 public: 65 virtual void ANNOTATE("Super pure virtual") noneGC() = 0; 66 virtual void allGC() = 0; 67 virtual void onSuper() { asm(""); } 68 void nonVirtualFunc() { asm(""); } 69 }; 70 71 class Sub1 : public Super { 72 public: 73 void noneGC() override { foo(); } 74 void someGC() override ANNOTATE("Sub1 override") ANNOTATE("second attr") { 75 foo(); 76 } 77 void someGC(int) override ANNOTATE("Sub1 override for int overload") { 78 foo(); 79 } 80 void allGC() override { 81 foo(); 82 bar(); 83 } 84 void sibGC() override { foo(); } 85 void onBase() override { foo(); } 86 } ANNOTATE("CSU1") ANNOTATE("CSU2"); 87 88 class Sub2 : public Super { 89 public: 90 void noneGC() override { foo(); } 91 void someGC() override { 92 foo(); 93 bar(); 94 } 95 void someGC(int) override { 96 foo(); 97 bar(); 98 } 99 void allGC() override { 100 foo(); 101 bar(); 102 } 103 void sibGC() override { foo(); } 104 }; 105 106 class Sibling : public Base { 107 public: 108 virtual void noneGC() { foo(); } 109 void someGC() override { 110 foo(); 111 bar(); 112 } 113 void someGC(int) override { 114 foo(); 115 bar(); 116 } 117 virtual void allGC() { 118 foo(); 119 bar(); 120 } 121 void sibGC() override { bar(); } 122 }; 123 124 class AutoSuppressGC { 125 public: 126 AutoSuppressGC() {} 127 ~AutoSuppressGC() {} 128 } ANNOTATE("Suppress GC"); 129 130 void use(Cell*) { asm(""); } 131 132 class nsISupports { 133 public: 134 virtual ANNOTATE("Can run script") void danger() { asm(""); } 135 136 virtual ~nsISupports() = 0; 137 }; 138 139 class nsIPrincipal : public nsISupports { 140 public: 141 ~nsIPrincipal() override {}; 142 }; 143 144 struct JSPrincipals { 145 int debugToken; 146 JSPrincipals() = default; 147 virtual ~JSPrincipals() { GC(); } 148 }; 149 150 class nsJSPrincipals : public nsIPrincipal, public JSPrincipals { 151 public: 152 void Release() { delete this; } 153 }; 154 155 class SafePrincipals : public nsIPrincipal { 156 public: 157 ~SafePrincipals() { foo(); } 158 }; 159 160 void f() { 161 Sub1 s1; 162 Sub2 s2; 163 164 static Cell cell; 165 { 166 Cell* c1 = &cell; 167 s1.noneGC(); 168 use(c1); 169 } 170 { 171 Cell* c2 = &cell; 172 s2.someGC(); 173 use(c2); 174 } 175 { 176 Cell* c3 = &cell; 177 s1.allGC(); 178 use(c3); 179 } 180 { 181 Cell* c4 = &cell; 182 s2.noneGC(); 183 use(c4); 184 } 185 { 186 Cell* c5 = &cell; 187 s2.someGC(); 188 use(c5); 189 } 190 { 191 Cell* c6 = &cell; 192 s2.allGC(); 193 use(c6); 194 } 195 196 Super* super = &s2; 197 { 198 Cell* c7 = &cell; 199 super->noneGC(); 200 use(c7); 201 } 202 { 203 Cell* c8 = &cell; 204 super->someGC(); 205 use(c8); 206 } 207 { 208 Cell* c9 = &cell; 209 super->allGC(); 210 use(c9); 211 } 212 213 { 214 Cell* c10 = &cell; 215 s1.functionField(); 216 use(c10); 217 } 218 { 219 Cell* c11 = &cell; 220 super->functionField(); 221 use(c11); 222 } 223 { 224 Cell* c12 = &cell; 225 super->sibGC(); 226 use(c12); 227 } 228 229 Base* base = &s2; 230 { 231 Cell* c13 = &cell; 232 base->sibGC(); 233 use(c13); 234 } 235 236 nsJSPrincipals pals; 237 { 238 Cell* c14 = &cell; 239 nsISupports* p = &pals; 240 p->danger(); 241 use(c14); 242 } 243 244 // Base defines, Sub1 overrides, static Super can call either. 245 { 246 Cell* c15 = &cell; 247 super->onBase(); 248 use(c15); 249 } 250 251 { 252 Cell* c16 = &cell; 253 s2.someGC(7); 254 use(c16); 255 } 256 257 { 258 Cell* c17 = &cell; 259 super->someGC(7); 260 use(c17); 261 } 262 263 { 264 nsJSPrincipals* princ = new nsJSPrincipals(); 265 Cell* c18 = &cell; 266 delete princ; // Can GC 267 use(c18); 268 } 269 270 { 271 nsJSPrincipals* princ = new nsJSPrincipals(); 272 nsISupports* supp = static_cast<nsISupports*>(princ); 273 Cell* c19 = &cell; 274 delete supp; // Can GC 275 use(c19); 276 } 277 278 { 279 auto* safe = new SafePrincipals(); 280 Cell* c20 = &cell; 281 delete safe; // Cannot GC 282 use(c20); 283 } 284 285 { 286 auto* safe = new SafePrincipals(); 287 nsISupports* supp = static_cast<nsISupports*>(safe); 288 Cell* c21 = &cell; 289 delete supp; // Compiler thinks destructor can GC. 290 use(c21); 291 } 292 } 293 294 template <typename Function> 295 void Call1(Function&& f) { 296 f(); 297 } 298 299 template <typename Function> 300 void Call2(Function&& f) { 301 f(); 302 } 303 304 void function_pointers() { 305 Cell cell; 306 307 { 308 auto* f = GC; 309 Cell* c22 = &cell; 310 f(); 311 use(c22); 312 } 313 314 { 315 auto* f = GC; 316 auto*& g = f; 317 Cell* c23 = &cell; 318 g(); 319 use(c23); 320 } 321 322 { 323 auto* f = GC; 324 Call1([&] { 325 Cell* c24 = &cell; 326 f(); 327 use(c24); 328 }); 329 } 330 } 331 332 // Use a separate function to test `mallocSizeOf` annotations. Bug 1872197: 333 // functions that are specialized on a lambda function and call that function 334 // will have that call get mixed up with other calls of lambdas defined within 335 // the same function. 336 void annotated_function_pointers() { 337 Cell cell; 338 339 // Variables with the specific name "mallocSizeOf" are 340 // annotated to not GC. (Heh... even though here, they 341 // *do* GC!) 342 343 { 344 auto* mallocSizeOf = GC; 345 Cell* c25 = &cell; 346 mallocSizeOf(); 347 use(c25); 348 } 349 350 { 351 auto* f = GC; 352 auto*& mallocSizeOf = f; 353 Cell* c26 = &cell; 354 mallocSizeOf(); 355 use(c26); 356 } 357 358 { 359 auto* mallocSizeOf = GC; 360 Call2([&] { 361 Cell* c27 = &cell; 362 mallocSizeOf(); 363 use(c27); 364 }); 365 } 366 }