javaAssertions.cpp revision 0:a61af66fc99e
133965Sjdp/*
278828Sobrien * Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
391041Sobrien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
438889Sjdp *
533965Sjdp * This code is free software; you can redistribute it and/or modify it
633965Sjdp * under the terms of the GNU General Public License version 2 only, as
733965Sjdp * published by the Free Software Foundation.
833965Sjdp *
933965Sjdp * This code is distributed in the hope that it will be useful, but WITHOUT
1033965Sjdp * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1133965Sjdp * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1233965Sjdp * version 2 for more details (a copy is included in the LICENSE file that
1333965Sjdp * accompanied this code).
1433965Sjdp *
1533965Sjdp * You should have received a copy of the GNU General Public License version
1689857Sobrien * 2 along with this work; if not, write to the Free Software Foundation,
1789857Sobrien * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1889857Sobrien *
1933965Sjdp * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
2033965Sjdp * CA 95054 USA or visit www.sun.com if you need additional information or
2133965Sjdp * have any questions.
2233965Sjdp *
2360484Sobrien */
2433965Sjdp
2589857Sobrien#include "incls/_precompiled.incl"
2689857Sobrien#include "incls/_javaAssertions.cpp.incl"
2789857Sobrien
2889857Sobrienbool                            JavaAssertions::_userDefault = false;
2989857Sobrienbool                            JavaAssertions::_sysDefault = false;
3089857SobrienJavaAssertions::OptionList*     JavaAssertions::_classes = 0;
3189857SobrienJavaAssertions::OptionList*     JavaAssertions::_packages = 0;
3291041Sobrien
3389857SobrienJavaAssertions::OptionList::OptionList(const char* name, bool enabled,
3489857Sobrien  OptionList* next) {
3591041Sobrien  assert(name != 0, "need a name");
3689857Sobrien  _name = name;
3789857Sobrien  _enabled = enabled;
3889857Sobrien  _next = next;
3989857Sobrien}
4089857Sobrien
4189857Sobrienint JavaAssertions::OptionList::count(OptionList* p) {
4289857Sobrien  int rc;
4389857Sobrien  for (rc = 0; p != 0; p = p->next(), ++rc) /* empty */;
4489857Sobrien  return rc;
45104834Sobrien}
4689857Sobrien
4789857Sobrienvoid JavaAssertions::addOption(const char* name, bool enable) {
4889857Sobrien  assert(name != 0, "must have a name");
4989857Sobrien
5089857Sobrien  // Copy the name.  The storage needs to exist for the the lifetime of the vm;
5189857Sobrien  // it is never freed, so will be leaked (along with other option strings -
5289857Sobrien  // e.g., bootclasspath) if a process creates/destroys multiple VMs.
5389857Sobrien  int len = (int)strlen(name);
5489857Sobrien  char *name_copy = NEW_C_HEAP_ARRAY(char, len + 1);
5589857Sobrien  strcpy(name_copy, name);
5689857Sobrien
5789857Sobrien  // Figure out which list the new item should go on.  Names that end in "..."
5889857Sobrien  // go on the package tree list.
5989857Sobrien  OptionList** head = &_classes;
6089857Sobrien  if (len >= 3 && strcmp(name_copy + len - 3, "...") == 0) {
6189857Sobrien    // Delete the "...".
6289857Sobrien    len -= 3;
6333965Sjdp    name_copy[len] = '\0';
6433965Sjdp    head = &_packages;
6533965Sjdp  }
6633965Sjdp
6738889Sjdp  // Convert class/package names to internal format.  Will have to convert back
6838889Sjdp  // when copying to java in createJavaAssertionStatusDirectives, but that
6938889Sjdp  // should happen only once.  Alternative would require that
7033965Sjdp  // JVM_DesiredAssertionStatus pass the external_name() to
7133965Sjdp  // JavaAssertion::enabled(), but that is done once per loaded class.
7233965Sjdp  for (int i = 0; i < len; ++i) {
7333965Sjdp    if (name_copy[i] == '.') name_copy[i] = '/';
7433965Sjdp  }
7533965Sjdp
7633965Sjdp  if (TraceJavaAssertions) {
7733965Sjdp    tty->print_cr("JavaAssertions: adding %s %s=%d",
7833965Sjdp      head == &_classes ? "class" : "package",
7933965Sjdp      name_copy[0] != '\0' ? name_copy : "'default'",
8033965Sjdp      enable);
8133965Sjdp  }
8233965Sjdp
8333965Sjdp  // Prepend a new item to the list.  Items added later take precedence, so
8433965Sjdp  // prepending allows us to stop searching the list after the first match.
8533965Sjdp  *head = new OptionList(name_copy, enable, *head);
8633965Sjdp}
8733965Sjdp
8833965Sjdpoop JavaAssertions::createAssertionStatusDirectives(TRAPS) {
8933965Sjdp  symbolHandle asd_sym = vmSymbolHandles::java_lang_AssertionStatusDirectives();
9033965Sjdp  klassOop k = SystemDictionary::resolve_or_fail(asd_sym, true, CHECK_NULL);
9133965Sjdp  instanceKlassHandle asd_klass (THREAD, k);
9233965Sjdp  asd_klass->initialize(CHECK_NULL);
9333965Sjdp  Handle h = asd_klass->allocate_instance_handle(CHECK_NULL);
9433965Sjdp
9533965Sjdp  int len;
9633965Sjdp  typeArrayOop t;
9733965Sjdp  len = OptionList::count(_packages);
9833965Sjdp  objArrayOop pn = oopFactory::new_objArray(SystemDictionary::string_klass(), len, CHECK_NULL);
9933965Sjdp  objArrayHandle pkgNames (THREAD, pn);
10033965Sjdp  t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL);
10133965Sjdp  typeArrayHandle pkgEnabled(THREAD, t);
10233965Sjdp  fillJavaArrays(_packages, len, pkgNames, pkgEnabled, CHECK_NULL);
10333965Sjdp
10433965Sjdp  len = OptionList::count(_classes);
10533965Sjdp  objArrayOop cn = oopFactory::new_objArray(SystemDictionary::string_klass(), len, CHECK_NULL);
10633965Sjdp  objArrayHandle classNames (THREAD, cn);
10733965Sjdp  t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL);
10833965Sjdp  typeArrayHandle classEnabled(THREAD, t);
10933965Sjdp  fillJavaArrays(_classes, len, classNames, classEnabled, CHECK_NULL);
11033965Sjdp
11133965Sjdp  java_lang_AssertionStatusDirectives::set_packages(h(), pkgNames());
11233965Sjdp  java_lang_AssertionStatusDirectives::set_packageEnabled(h(), pkgEnabled());
11333965Sjdp  java_lang_AssertionStatusDirectives::set_classes(h(), classNames());
11433965Sjdp  java_lang_AssertionStatusDirectives::set_classEnabled(h(), classEnabled());
11533965Sjdp  java_lang_AssertionStatusDirectives::set_deflt(h(), userClassDefault());
11633965Sjdp  return h();
11733965Sjdp}
11833965Sjdp
11933965Sjdpvoid JavaAssertions::fillJavaArrays(const OptionList* p, int len,
12033965SjdpobjArrayHandle names, typeArrayHandle enabled, TRAPS) {
12133965Sjdp  // Fill in the parallel names and enabled (boolean) arrays.  Start at the end
12291041Sobrien  // of the array and work backwards, so the order of items in the arrays
12333965Sjdp  // matches the order on the command line (the list is in reverse order, since
12433965Sjdp  // it was created by prepending successive items from the command line).
12533965Sjdp  int index;
12633965Sjdp  for (index = len - 1; p != 0; p = p->next(), --index) {
12733965Sjdp    assert(index >= 0, "length does not match list");
12833965Sjdp    Handle s = java_lang_String::create_from_str(p->name(), CHECK);
12933965Sjdp    s = java_lang_String::char_converter(s, '/', '.', CHECK);
13033965Sjdp    names->obj_at_put(index, s());
13133965Sjdp    enabled->bool_at_put(index, p->enabled());
13233965Sjdp  }
13389857Sobrien  assert(index == -1, "length does not match list");
13491041Sobrien}
13533965Sjdp
13689857Sobrieninline JavaAssertions::OptionList*
13789857SobrienJavaAssertions::match_class(const char* classname) {
13889857Sobrien  for (OptionList* p = _classes; p != 0; p = p->next()) {
13989857Sobrien    if (strcmp(p->name(), classname) == 0) {
14089857Sobrien      return p;
14189857Sobrien    }
14233965Sjdp  }
14389857Sobrien  return 0;
14489857Sobrien}
14533965Sjdp
14633965SjdpJavaAssertions::OptionList*
14733965SjdpJavaAssertions::match_package(const char* classname) {
14833965Sjdp  // Search the package list for any items that apply to classname.  Each
14933965Sjdp  // sub-package in classname is checked, from most-specific to least, until one
15033965Sjdp  // is found.
15133965Sjdp  if (_packages == 0) return 0;
15233965Sjdp
15333965Sjdp  // Find the length of the "most-specific" package in classname.  If classname
15433965Sjdp  // does not include a package, length will be 0 which will match items for the
15533965Sjdp  // default package (from options "-ea:..."  or "-da:...").
15633965Sjdp  size_t len = strlen(classname);
15733965Sjdp  for (/* empty */; len > 0 && classname[len] != '/'; --len) /* empty */;
15833965Sjdp
15933965Sjdp  do {
16033965Sjdp    assert(len == 0 || classname[len] == '/', "not a package name");
16160484Sobrien    for (OptionList* p = _packages; p != 0; p = p->next()) {
16233965Sjdp      if (strncmp(p->name(), classname, len) == 0 && p->name()[len] == '\0') {
16333965Sjdp        return p;
16433965Sjdp      }
16533965Sjdp    }
16689857Sobrien
16733965Sjdp    // Find the length of the next package, taking care to avoid decrementing
16833965Sjdp    // past 0 (len is unsigned).
16933965Sjdp    while (len > 0 && classname[--len] != '/') /* empty */;
17033965Sjdp  } while (len > 0);
17133965Sjdp
17233965Sjdp  return 0;
17333965Sjdp}
17433965Sjdp
17533965Sjdpinline void JavaAssertions::trace(const char* name,
17633965Sjdpconst char* typefound, const char* namefound, bool enabled) {
17733965Sjdp  if (TraceJavaAssertions) {
17833965Sjdp    tty->print_cr("JavaAssertions:  search for %s found %s %s=%d",
17933965Sjdp      name, typefound, namefound[0] != '\0' ? namefound : "'default'", enabled);
18033965Sjdp  }
18133965Sjdp}
18233965Sjdp
18333965Sjdpbool JavaAssertions::enabled(const char* classname, bool systemClass) {
18433965Sjdp  assert(classname != 0, "must have a classname");
18533965Sjdp
18633965Sjdp  // This will be slow if the number of assertion options on the command line is
18791041Sobrien  // large--it traverses two lists, one of them multiple times.  Could use a
18833965Sjdp  // single n-ary tree instead of lists if someone ever notices.
18977298Sobrien
19077298Sobrien  // First check options that apply to classes.  If we find a match we're done.
19177298Sobrien  OptionList* p;
19277298Sobrien  if (p = match_class(classname)) {
19377298Sobrien    trace(classname, "class", p->name(), p->enabled());
19477298Sobrien    return p->enabled();
19533965Sjdp  }
19633965Sjdp
19733965Sjdp  // Now check packages, from most specific to least.
19892828Sobrien  if (p = match_package(classname)) {
19933965Sjdp    trace(classname, "package", p->name(), p->enabled());
20033965Sjdp    return p->enabled();
20133965Sjdp  }
20289857Sobrien
20360484Sobrien  // No match.  Return the default status.
20433965Sjdp  bool result = systemClass ? systemClassDefault() : userClassDefault();
20589857Sobrien  trace(classname, systemClass ? "system" : "user", "default", result);
20633965Sjdp  return result;
20733965Sjdp}
20877298Sobrien