1 /*
   2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "jvm.h"
  27 #include "classfile/systemDictionary.hpp"
  28 #include "code/codeCache.hpp"
  29 #include "code/icBuffer.hpp"
  30 #include "code/nmethod.hpp"
  31 #include "code/vtableStubs.hpp"
  32 #include "compiler/compileBroker.hpp"
  33 #include "compiler/disassembler.hpp"
  34 #include "gc/shared/collectedHeap.hpp"
  35 #include "interpreter/bytecodeHistogram.hpp"
  36 #include "interpreter/interpreter.hpp"
  37 #include "memory/resourceArea.hpp"
  38 #include "memory/universe.hpp"
  39 #include "oops/oop.inline.hpp"
  40 #include "prims/privilegedStack.hpp"
  41 #include "runtime/arguments.hpp"
  42 #include "runtime/atomic.hpp"
  43 #include "runtime/frame.hpp"
  44 #include "runtime/java.hpp"
  45 #include "runtime/os.hpp"
  46 #include "runtime/sharedRuntime.hpp"
  47 #include "runtime/stubCodeGenerator.hpp"
  48 #include "runtime/stubRoutines.hpp"
  49 #include "runtime/thread.inline.hpp"
  50 #include "runtime/vframe.hpp"
  51 #include "runtime/vm_version.hpp"
  52 #include "services/heapDumper.hpp"
  53 #include "utilities/defaultStream.hpp"
  54 #include "utilities/events.hpp"
  55 #include "utilities/formatBuffer.hpp"
  56 #include "utilities/macros.hpp"
  57 #include "utilities/vmError.hpp"
  58 
  59 #include <stdio.h>
  60 
  61 #ifndef ASSERT
  62 #  ifdef _DEBUG
  63    // NOTE: don't turn the lines below into a comment -- if you're getting
  64    // a compile error here, change the settings to define ASSERT
  65    ASSERT should be defined when _DEBUG is defined.  It is not intended to be used for debugging
  66    functions that do not slow down the system too much and thus can be left in optimized code.
  67    On the other hand, the code should not be included in a production version.
  68 #  endif // _DEBUG
  69 #endif // ASSERT
  70 
  71 
  72 #ifdef _DEBUG
  73 #  ifndef ASSERT
  74      configuration error: ASSERT must be defined in debug version
  75 #  endif // ASSERT
  76 #endif // _DEBUG
  77 
  78 
  79 #ifdef PRODUCT
  80 #  if -defined _DEBUG || -defined ASSERT
  81      configuration error: ASSERT et al. must not be defined in PRODUCT version
  82 #  endif
  83 #endif // PRODUCT
  84 
  85 ATTRIBUTE_PRINTF(1, 2)
  86 void warning(const char* format, ...) {
  87   if (PrintWarnings) {
  88     FILE* const err = defaultStream::error_stream();
  89     jio_fprintf(err, "%s warning: ", VM_Version::vm_name());
  90     va_list ap;
  91     va_start(ap, format);
  92     vfprintf(err, format, ap);
  93     va_end(ap);
  94     fputc('\n', err);
  95   }
  96   if (BreakAtWarning) BREAKPOINT;
  97 }
  98 
  99 #ifndef PRODUCT
 100 
 101 #define is_token_break(ch) (isspace(ch) || (ch) == ',')
 102 
 103 static const char* last_file_name = NULL;
 104 static int         last_line_no   = -1;
 105 
 106 // assert/guarantee/... may happen very early during VM initialization.
 107 // Don't rely on anything that is initialized by Threads::create_vm(). For
 108 // example, don't use tty.
 109 bool error_is_suppressed(const char* file_name, int line_no) {
 110   // The following 1-element cache requires that passed-in
 111   // file names are always only constant literals.
 112   if (file_name == last_file_name && line_no == last_line_no)  return true;
 113 
 114   int file_name_len = (int)strlen(file_name);
 115   char separator = os::file_separator()[0];
 116   const char* base_name = strrchr(file_name, separator);
 117   if (base_name == NULL)
 118     base_name = file_name;
 119 
 120   // scan the SuppressErrorAt option
 121   const char* cp = SuppressErrorAt;
 122   for (;;) {
 123     const char* sfile;
 124     int sfile_len;
 125     int sline;
 126     bool noisy;
 127     while ((*cp) != '\0' && is_token_break(*cp))  cp++;
 128     if ((*cp) == '\0')  break;
 129     sfile = cp;
 130     while ((*cp) != '\0' && !is_token_break(*cp) && (*cp) != ':')  cp++;
 131     sfile_len = cp - sfile;
 132     if ((*cp) == ':')  cp++;
 133     sline = 0;
 134     while ((*cp) != '\0' && isdigit(*cp)) {
 135       sline *= 10;
 136       sline += (*cp) - '0';
 137       cp++;
 138     }
 139     // "file:line!" means the assert suppression is not silent
 140     noisy = ((*cp) == '!');
 141     while ((*cp) != '\0' && !is_token_break(*cp))  cp++;
 142     // match the line
 143     if (sline != 0) {
 144       if (sline != line_no)  continue;
 145     }
 146     // match the file
 147     if (sfile_len > 0) {
 148       const char* look = file_name;
 149       const char* look_max = file_name + file_name_len - sfile_len;
 150       const char* foundp;
 151       bool match = false;
 152       while (!match
 153              && (foundp = strchr(look, sfile[0])) != NULL
 154              && foundp <= look_max) {
 155         match = true;
 156         for (int i = 1; i < sfile_len; i++) {
 157           if (sfile[i] != foundp[i]) {
 158             match = false;
 159             break;
 160           }
 161         }
 162         look = foundp + 1;
 163       }
 164       if (!match)  continue;
 165     }
 166     // got a match!
 167     if (noisy) {
 168       fdStream out(defaultStream::output_fd());
 169       out.print_raw("[error suppressed at ");
 170       out.print_raw(base_name);
 171       char buf[16];
 172       jio_snprintf(buf, sizeof(buf), ":%d]", line_no);
 173       out.print_raw_cr(buf);
 174     } else {
 175       // update 1-element cache for fast silent matches
 176       last_file_name = file_name;
 177       last_line_no   = line_no;
 178     }
 179     return true;
 180   }
 181 
 182   if (!VMError::is_error_reported() && !SuppressFatalErrorMessage) {
 183     // print a friendly hint:
 184     fdStream out(defaultStream::output_fd());
 185     out.print_raw_cr("# To suppress the following error report, specify this argument");
 186     out.print_raw   ("# after -XX: or in .hotspotrc:  SuppressErrorAt=");
 187     out.print_raw   (base_name);
 188     char buf[16];
 189     jio_snprintf(buf, sizeof(buf), ":%d", line_no);
 190     out.print_raw_cr(buf);
 191   }
 192   return false;
 193 }
 194 
 195 #undef is_token_break
 196 
 197 #else
 198 
 199 // Place-holder for non-existent suppression check:
 200 #define error_is_suppressed(file_name, line_no) (false)
 201 
 202 #endif // !PRODUCT
 203 
 204 void report_vm_error(const char* file, int line, const char* error_msg)
 205 {
 206   report_vm_error(file, line, error_msg, "%s", "");
 207 }
 208 
 209 void report_vm_error(const char* file, int line, const char* error_msg, const char* detail_fmt, ...)
 210 {
 211   if (Debugging || error_is_suppressed(file, line)) return;
 212   va_list detail_args;
 213   va_start(detail_args, detail_fmt);
 214   VMError::report_and_die(Thread::current_or_null(), file, line, error_msg, detail_fmt, detail_args);
 215   va_end(detail_args);
 216 }
 217 
 218 void report_vm_status_error(const char* file, int line, const char* error_msg,
 219                             int status, const char* detail) {
 220   report_vm_error(file, line, error_msg, "error %s(%d), %s", os::errno_name(status), status, detail);
 221 }
 222 
 223 void report_fatal(const char* file, int line, const char* detail_fmt, ...)
 224 {
 225   if (Debugging || error_is_suppressed(file, line)) return;
 226   va_list detail_args;
 227   va_start(detail_args, detail_fmt);
 228   VMError::report_and_die(Thread::current_or_null(), file, line, "fatal error", detail_fmt, detail_args);
 229   va_end(detail_args);
 230 }
 231 
 232 void report_vm_out_of_memory(const char* file, int line, size_t size,
 233                              VMErrorType vm_err_type, const char* detail_fmt, ...) {
 234   if (Debugging) return;
 235   va_list detail_args;
 236   va_start(detail_args, detail_fmt);
 237   VMError::report_and_die(Thread::current_or_null(), file, line, size, vm_err_type, detail_fmt, detail_args);
 238   va_end(detail_args);
 239 
 240   // The UseOSErrorReporting option in report_and_die() may allow a return
 241   // to here. If so then we'll have to figure out how to handle it.
 242   guarantee(false, "report_and_die() should not return here");
 243 }
 244 
 245 void report_should_not_call(const char* file, int line) {
 246   report_vm_error(file, line, "ShouldNotCall()");
 247 }
 248 
 249 void report_should_not_reach_here(const char* file, int line) {
 250   report_vm_error(file, line, "ShouldNotReachHere()");
 251 }
 252 
 253 void report_unimplemented(const char* file, int line) {
 254   report_vm_error(file, line, "Unimplemented()");
 255 }
 256 
 257 #ifdef ASSERT
 258 bool is_executing_unit_tests() {
 259   return ExecutingUnitTests;
 260 }
 261 
 262 void report_assert_msg(const char* msg, ...) {
 263   va_list ap;
 264   va_start(ap, msg);
 265 
 266   fprintf(stderr, "assert failed: %s\n", err_msg(FormatBufferDummy(), msg, ap).buffer());
 267 
 268   va_end(ap);
 269 }
 270 #endif // ASSERT
 271 
 272 void report_untested(const char* file, int line, const char* message) {
 273 #ifndef PRODUCT
 274   warning("Untested: %s in %s: %d\n", message, file, line);
 275 #endif // !PRODUCT
 276 }
 277 
 278 void report_java_out_of_memory(const char* message) {
 279   static int out_of_memory_reported = 0;
 280 
 281   // A number of threads may attempt to report OutOfMemoryError at around the
 282   // same time. To avoid dumping the heap or executing the data collection
 283   // commands multiple times we just do it once when the first threads reports
 284   // the error.
 285   if (Atomic::cmpxchg(1, &out_of_memory_reported, 0) == 0) {
 286     // create heap dump before OnOutOfMemoryError commands are executed
 287     if (HeapDumpOnOutOfMemoryError) {
 288       tty->print_cr("java.lang.OutOfMemoryError: %s", message);
 289       HeapDumper::dump_heap_from_oome();
 290     }
 291 
 292     if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
 293       VMError::report_java_out_of_memory(message);
 294     }
 295 
 296     if (CrashOnOutOfMemoryError) {
 297       tty->print_cr("Aborting due to java.lang.OutOfMemoryError: %s", message);
 298       fatal("OutOfMemory encountered: %s", message);
 299     }
 300 
 301     if (ExitOnOutOfMemoryError) {
 302       tty->print_cr("Terminating due to java.lang.OutOfMemoryError: %s", message);
 303       os::exit(3);
 304     }
 305   }
 306 }
 307 
 308 // ------ helper functions for debugging go here ------------
 309 
 310 // All debug entries should be wrapped with a stack allocated
 311 // Command object. It makes sure a resource mark is set and
 312 // flushes the logfile to prevent file sharing problems.
 313 
 314 class Command : public StackObj {
 315  private:
 316   ResourceMark rm;
 317   ResetNoHandleMark rnhm;
 318   HandleMark   hm;
 319   bool debug_save;
 320  public:
 321   static int level;
 322   Command(const char* str) {
 323     debug_save = Debugging;
 324     Debugging = true;
 325     if (level++ > 0)  return;
 326     tty->cr();
 327     tty->print_cr("\"Executing %s\"", str);
 328   }
 329 
 330   ~Command() {
 331         tty->flush();
 332         Debugging = debug_save;
 333         level--;
 334   }
 335 };
 336 
 337 int Command::level = 0;
 338 
 339 #ifndef PRODUCT
 340 
 341 extern "C" void blob(CodeBlob* cb) {
 342   Command c("blob");
 343   cb->print();
 344 }
 345 
 346 
 347 extern "C" void dump_vtable(address p) {
 348   Command c("dump_vtable");
 349   Klass* k = (Klass*)p;
 350   k->vtable().print();
 351 }
 352 
 353 
 354 extern "C" void nm(intptr_t p) {
 355   // Actually we look through all CodeBlobs (the nm name has been kept for backwards compatability)
 356   Command c("nm");
 357   CodeBlob* cb = CodeCache::find_blob((address)p);
 358   if (cb == NULL) {
 359     tty->print_cr("NULL");
 360   } else {
 361     cb->print();
 362   }
 363 }
 364 
 365 
 366 extern "C" void disnm(intptr_t p) {
 367   Command c("disnm");
 368   CodeBlob* cb = CodeCache::find_blob((address) p);
 369   if (cb != NULL) {
 370     nmethod* nm = cb->as_nmethod_or_null();
 371     if (nm != NULL) {
 372       nm->print();
 373     } else {
 374       cb->print();
 375     }
 376     Disassembler::decode(cb);
 377   }
 378 }
 379 
 380 
 381 extern "C" void printnm(intptr_t p) {
 382   char buffer[256];
 383   sprintf(buffer, "printnm: " INTPTR_FORMAT, p);
 384   Command c(buffer);
 385   CodeBlob* cb = CodeCache::find_blob((address) p);
 386   if (cb->is_nmethod()) {
 387     nmethod* nm = (nmethod*)cb;
 388     nm->print_nmethod(true);
 389   }
 390 }
 391 
 392 
 393 extern "C" void universe() {
 394   Command c("universe");
 395   Universe::print_on(tty);
 396 }
 397 
 398 
 399 extern "C" void verify() {
 400   // try to run a verify on the entire system
 401   // note: this may not be safe if we're not at a safepoint; for debugging,
 402   // this manipulates the safepoint settings to avoid assertion failures
 403   Command c("universe verify");
 404   bool safe = SafepointSynchronize::is_at_safepoint();
 405   if (!safe) {
 406     tty->print_cr("warning: not at safepoint -- verify may fail");
 407     SafepointSynchronize::set_is_at_safepoint();
 408   }
 409   // Ensure Eden top is correct before verification
 410   Universe::heap()->prepare_for_verify();
 411   Universe::verify();
 412   if (!safe) SafepointSynchronize::set_is_not_at_safepoint();
 413 }
 414 
 415 
 416 extern "C" void pp(void* p) {
 417   Command c("pp");
 418   FlagSetting fl(PrintVMMessages, true);
 419   FlagSetting f2(DisplayVMOutput, true);
 420   if (Universe::heap()->is_in(p)) {
 421     oop obj = oop(p);
 422     obj->print();
 423   } else {
 424     tty->print(PTR_FORMAT, p2i(p));
 425   }
 426 }
 427 
 428 
 429 // pv: print vm-printable object
 430 extern "C" void pa(intptr_t p)   { ((AllocatedObj*) p)->print(); }
 431 extern "C" void findpc(intptr_t x);
 432 
 433 #endif // !PRODUCT
 434 
 435 extern "C" void ps() { // print stack
 436   if (Thread::current_or_null() == NULL) return;
 437   Command c("ps");
 438 
 439 
 440   // Prints the stack of the current Java thread
 441   JavaThread* p = JavaThread::active();
 442   tty->print(" for thread: ");
 443   p->print();
 444   tty->cr();
 445 
 446   if (p->has_last_Java_frame()) {
 447     // If the last_Java_fp is set we are in C land and
 448     // can call the standard stack_trace function.
 449 #ifdef PRODUCT
 450     p->print_stack();
 451   } else {
 452     tty->print_cr("Cannot find the last Java frame, printing stack disabled.");
 453 #else // !PRODUCT
 454     p->trace_stack();
 455   } else {
 456     frame f = os::current_frame();
 457     RegisterMap reg_map(p);
 458     f = f.sender(&reg_map);
 459     tty->print("(guessing starting frame id=" PTR_FORMAT " based on current fp)\n", p2i(f.id()));
 460     p->trace_stack_from(vframe::new_vframe(&f, &reg_map, p));
 461     f.pd_ps();
 462 #endif // PRODUCT
 463   }
 464 
 465 }
 466 
 467 extern "C" void pfl() {
 468   // print frame layout
 469   Command c("pfl");
 470   JavaThread* p = JavaThread::active();
 471   tty->print(" for thread: ");
 472   p->print();
 473   tty->cr();
 474   if (p->has_last_Java_frame()) {
 475     p->print_frame_layout();
 476   }
 477 }
 478 
 479 #ifndef PRODUCT
 480 
 481 extern "C" void psf() { // print stack frames
 482   {
 483     Command c("psf");
 484     JavaThread* p = JavaThread::active();
 485     tty->print(" for thread: ");
 486     p->print();
 487     tty->cr();
 488     if (p->has_last_Java_frame()) {
 489       p->trace_frames();
 490     }
 491   }
 492 }
 493 
 494 
 495 extern "C" void threads() {
 496   Command c("threads");
 497   Threads::print(false, true);
 498 }
 499 
 500 
 501 extern "C" void psd() {
 502   Command c("psd");
 503   SystemDictionary::print();
 504 }
 505 
 506 #endif // !PRODUCT
 507 
 508 extern "C" void pss() { // print all stacks
 509   if (Thread::current_or_null() == NULL) return;
 510   Command c("pss");
 511   Threads::print(true, PRODUCT_ONLY(false) NOT_PRODUCT(true));
 512 }
 513 
 514 #ifndef PRODUCT
 515 
 516 extern "C" void debug() {               // to set things up for compiler debugging
 517   Command c("debug");
 518   WizardMode = true;
 519   PrintVMMessages = PrintCompilation = true;
 520   PrintInlining = PrintAssembly = true;
 521   tty->flush();
 522 }
 523 
 524 
 525 extern "C" void ndebug() {              // undo debug()
 526   Command c("ndebug");
 527   PrintCompilation = false;
 528   PrintInlining = PrintAssembly = false;
 529   tty->flush();
 530 }
 531 
 532 
 533 extern "C" void flush()  {
 534   Command c("flush");
 535   tty->flush();
 536 }
 537 
 538 extern "C" void events() {
 539   Command c("events");
 540   Events::print();
 541 }
 542 
 543 extern "C" Method* findm(intptr_t pc) {
 544   Command c("findm");
 545   nmethod* nm = CodeCache::find_nmethod((address)pc);
 546   return (nm == NULL) ? (Method*)NULL : nm->method();
 547 }
 548 
 549 
 550 extern "C" nmethod* findnm(intptr_t addr) {
 551   Command c("findnm");
 552   return  CodeCache::find_nmethod((address)addr);
 553 }
 554 
 555 // Another interface that isn't ambiguous in dbx.
 556 // Can we someday rename the other find to hsfind?
 557 extern "C" void hsfind(intptr_t x) {
 558   Command c("hsfind");
 559   os::print_location(tty, x, false);
 560 }
 561 
 562 
 563 extern "C" void find(intptr_t x) {
 564   Command c("find");
 565   os::print_location(tty, x, false);
 566 }
 567 
 568 
 569 extern "C" void findpc(intptr_t x) {
 570   Command c("findpc");
 571   os::print_location(tty, x, true);
 572 }
 573 
 574 
 575 // Need method pointer to find bcp, when not in permgen.
 576 extern "C" void findbcp(intptr_t method, intptr_t bcp) {
 577   Command c("findbcp");
 578   Method* mh = (Method*)method;
 579   if (!mh->is_native()) {
 580     tty->print_cr("bci_from(%p) = %d; print_codes():",
 581                         mh, mh->bci_from(address(bcp)));
 582     mh->print_codes_on(tty);
 583   }
 584 }
 585 
 586 // int versions of all methods to avoid having to type type casts in the debugger
 587 
 588 void pp(intptr_t p)          { pp((void*)p); }
 589 void pp(oop p)               { pp((void*)p); }
 590 
 591 void help() {
 592   Command c("help");
 593   tty->print_cr("basic");
 594   tty->print_cr("  pp(void* p)   - try to make sense of p");
 595   tty->print_cr("  pv(intptr_t p)- ((PrintableResourceObj*) p)->print()");
 596   tty->print_cr("  ps()          - print current thread stack");
 597   tty->print_cr("  pss()         - print all thread stacks");
 598   tty->print_cr("  pm(int pc)    - print Method* given compiled PC");
 599   tty->print_cr("  findm(intptr_t pc) - finds Method*");
 600   tty->print_cr("  find(intptr_t x)   - finds & prints nmethod/stub/bytecode/oop based on pointer into it");
 601   tty->print_cr("  pns(void* sp, void* fp, void* pc)  - print native (i.e. mixed) stack trace. E.g.");
 602   tty->print_cr("                   pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or");
 603   tty->print_cr("                   pns($sp, $ebp, $pc) on Linux/x86 or");
 604   tty->print_cr("                   pns($sp, 0, $pc)    on Linux/ppc64 or");
 605   tty->print_cr("                   pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC");
 606   tty->print_cr("                 - in gdb do 'set overload-resolution off' before calling pns()");
 607   tty->print_cr("                 - in dbx do 'frame 1' before calling pns()");
 608 
 609   tty->print_cr("misc.");
 610   tty->print_cr("  flush()       - flushes the log file");
 611   tty->print_cr("  events()      - dump events from ring buffers");
 612 
 613 
 614   tty->print_cr("compiler debugging");
 615   tty->print_cr("  debug()       - to set things up for compiler debugging");
 616   tty->print_cr("  ndebug()      - undo debug");
 617 }
 618 
 619 extern "C" void pns(void* sp, void* fp, void* pc) { // print native stack
 620   Command c("pns");
 621   static char buf[O_BUFLEN];
 622   Thread* t = Thread::current_or_null();
 623   // Call generic frame constructor (certain arguments may be ignored)
 624   frame fr(sp, fp, pc);
 625   VMError::print_native_stack(tty, fr, t, buf, sizeof(buf));
 626 }
 627 
 628 //
 629 // This version of pns() will not work when called from the debugger, but is
 630 // useful when called from within hotspot code. The advantages over pns()
 631 // are not having to pass in any arguments, and it will work on Windows/x64.
 632 //
 633 // WARNING: Only intended for use when debugging. Do not leave calls to
 634 // pns2() in committed source (product or debug).
 635 //
 636 extern "C" void pns2() { // print native stack
 637   Command c("pns2");
 638   static char buf[O_BUFLEN];
 639   if (os::platform_print_native_stack(tty, NULL, buf, sizeof(buf))) {
 640     // We have printed the native stack in platform-specific code,
 641     // so nothing else to do in this case.
 642   } else {
 643     Thread* t = Thread::current_or_null();
 644     frame fr = os::current_frame();
 645     VMError::print_native_stack(tty, fr, t, buf, sizeof(buf));
 646   }
 647 }
 648 
 649 #endif // !PRODUCT
 650 
 651 //////////////////////////////////////////////////////////////////////////////
 652 // Test multiple STATIC_ASSERT forms in various scopes.
 653 
 654 #ifndef PRODUCT
 655 
 656 // namespace scope
 657 STATIC_ASSERT(true);
 658 STATIC_ASSERT(true);
 659 STATIC_ASSERT(1 == 1);
 660 STATIC_ASSERT(0 == 0);
 661 
 662 void test_multiple_static_assert_forms_in_function_scope() {
 663   STATIC_ASSERT(true);
 664   STATIC_ASSERT(true);
 665   STATIC_ASSERT(0 == 0);
 666   STATIC_ASSERT(1 == 1);
 667 }
 668 
 669 // class scope
 670 struct TestMultipleStaticAssertFormsInClassScope {
 671   STATIC_ASSERT(true);
 672   STATIC_ASSERT(true);
 673   STATIC_ASSERT(0 == 0);
 674   STATIC_ASSERT(1 == 1);
 675 };
 676 
 677 #endif // !PRODUCT