javaAssertions.cpp revision 1472:c18cbe5936b8
1228753Smm/*
2231200Smm * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
3228753Smm * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4228753Smm *
5228753Smm * This code is free software; you can redistribute it and/or modify it
6228753Smm * under the terms of the GNU General Public License version 2 only, as
7228753Smm * published by the Free Software Foundation.
8228753Smm *
9228753Smm * This code is distributed in the hope that it will be useful, but WITHOUT
10228753Smm * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11228753Smm * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12228753Smm * version 2 for more details (a copy is included in the LICENSE file that
13228753Smm * accompanied this code).
14228753Smm *
15228753Smm * You should have received a copy of the GNU General Public License version
16228753Smm * 2 along with this work; if not, write to the Free Software Foundation,
17228753Smm * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18228753Smm *
19228753Smm * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20228753Smm * or visit www.oracle.com if you need additional information or have any
21228753Smm * questions.
22228753Smm *
23228753Smm */
24228753Smm
25228753Smm#include "incls/_precompiled.incl"
26228753Smm#include "incls/_javaAssertions.cpp.incl"
27228753Smm
28228753Smmbool                            JavaAssertions::_userDefault = false;
29231200Smmbool                            JavaAssertions::_sysDefault = false;
30228753SmmJavaAssertions::OptionList*     JavaAssertions::_classes = 0;
31228753SmmJavaAssertions::OptionList*     JavaAssertions::_packages = 0;
32228753Smm
33228753SmmJavaAssertions::OptionList::OptionList(const char* name, bool enabled,
34228753Smm  OptionList* next) {
35228753Smm  assert(name != 0, "need a name");
36228753Smm  _name = name;
37228753Smm  _enabled = enabled;
38228753Smm  _next = next;
39228753Smm}
40228753Smm
41228753Smmint JavaAssertions::OptionList::count(OptionList* p) {
42228753Smm  int rc;
43228753Smm  for (rc = 0; p != 0; p = p->next(), ++rc) /* empty */;
44228753Smm  return rc;
45228753Smm}
46228753Smm
47228753Smmvoid JavaAssertions::addOption(const char* name, bool enable) {
48228753Smm  assert(name != 0, "must have a name");
49228753Smm
50228753Smm  // Copy the name.  The storage needs to exist for the the lifetime of the vm;
51228753Smm  // it is never freed, so will be leaked (along with other option strings -
52228753Smm  // e.g., bootclasspath) if a process creates/destroys multiple VMs.
53228753Smm  int len = (int)strlen(name);
54228753Smm  char *name_copy = NEW_C_HEAP_ARRAY(char, len + 1);
55228753Smm  strcpy(name_copy, name);
56228753Smm
57228753Smm  // Figure out which list the new item should go on.  Names that end in "..."
58228753Smm  // go on the package tree list.
59228753Smm  OptionList** head = &_classes;
60228753Smm  if (len >= 3 && strcmp(name_copy + len - 3, "...") == 0) {
61228753Smm    // Delete the "...".
62228753Smm    len -= 3;
63231200Smm    name_copy[len] = '\0';
64231200Smm    head = &_packages;
65231200Smm  }
66231200Smm
67231200Smm  // Convert class/package names to internal format.  Will have to convert back
68231200Smm  // when copying to java in createJavaAssertionStatusDirectives, but that
69231200Smm  // should happen only once.  Alternative would require that
70228753Smm  // JVM_DesiredAssertionStatus pass the external_name() to
71228753Smm  // JavaAssertion::enabled(), but that is done once per loaded class.
72231200Smm  for (int i = 0; i < len; ++i) {
73231200Smm    if (name_copy[i] == '.') name_copy[i] = '/';
74231200Smm  }
75231200Smm
76231200Smm  if (TraceJavaAssertions) {
77231200Smm    tty->print_cr("JavaAssertions: adding %s %s=%d",
78231200Smm      head == &_classes ? "class" : "package",
79231200Smm      name_copy[0] != '\0' ? name_copy : "'default'",
80231200Smm      enable);
81228753Smm  }
82228753Smm
83228753Smm  // Prepend a new item to the list.  Items added later take precedence, so
84228753Smm  // prepending allows us to stop searching the list after the first match.
85228753Smm  *head = new OptionList(name_copy, enable, *head);
86228753Smm}
87228753Smm
88228753Smmoop JavaAssertions::createAssertionStatusDirectives(TRAPS) {
89228753Smm  symbolHandle asd_sym = vmSymbolHandles::java_lang_AssertionStatusDirectives();
90228753Smm  klassOop k = SystemDictionary::resolve_or_fail(asd_sym, true, CHECK_NULL);
91228753Smm  instanceKlassHandle asd_klass (THREAD, k);
92228753Smm  asd_klass->initialize(CHECK_NULL);
93228753Smm  Handle h = asd_klass->allocate_instance_handle(CHECK_NULL);
94228753Smm
95228753Smm  int len;
96228753Smm  typeArrayOop t;
97228753Smm  len = OptionList::count(_packages);
98228753Smm  objArrayOop pn = oopFactory::new_objArray(SystemDictionary::String_klass(), len, CHECK_NULL);
99228753Smm  objArrayHandle pkgNames (THREAD, pn);
100228753Smm  t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL);
101228753Smm  typeArrayHandle pkgEnabled(THREAD, t);
102228753Smm  fillJavaArrays(_packages, len, pkgNames, pkgEnabled, CHECK_NULL);
103228753Smm
104228753Smm  len = OptionList::count(_classes);
105228753Smm  objArrayOop cn = oopFactory::new_objArray(SystemDictionary::String_klass(), len, CHECK_NULL);
106228753Smm  objArrayHandle classNames (THREAD, cn);
107228753Smm  t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL);
108228753Smm  typeArrayHandle classEnabled(THREAD, t);
109228753Smm  fillJavaArrays(_classes, len, classNames, classEnabled, CHECK_NULL);
110228753Smm
111228753Smm  java_lang_AssertionStatusDirectives::set_packages(h(), pkgNames());
112231200Smm  java_lang_AssertionStatusDirectives::set_packageEnabled(h(), pkgEnabled());
113231200Smm  java_lang_AssertionStatusDirectives::set_classes(h(), classNames());
114231200Smm  java_lang_AssertionStatusDirectives::set_classEnabled(h(), classEnabled());
115231200Smm  java_lang_AssertionStatusDirectives::set_deflt(h(), userClassDefault());
116228753Smm  return h();
117231200Smm}
118231200Smm
119228753Smmvoid JavaAssertions::fillJavaArrays(const OptionList* p, int len,
120231200SmmobjArrayHandle names, typeArrayHandle enabled, TRAPS) {
121228753Smm  // Fill in the parallel names and enabled (boolean) arrays.  Start at the end
122231200Smm  // of the array and work backwards, so the order of items in the arrays
123231200Smm  // matches the order on the command line (the list is in reverse order, since
124231200Smm  // it was created by prepending successive items from the command line).
125231200Smm  int index;
126231200Smm  for (index = len - 1; p != 0; p = p->next(), --index) {
127231200Smm    assert(index >= 0, "length does not match list");
128231200Smm    Handle s = java_lang_String::create_from_str(p->name(), CHECK);
129228753Smm    s = java_lang_String::char_converter(s, '/', '.', CHECK);
130231200Smm    names->obj_at_put(index, s());
131228753Smm    enabled->bool_at_put(index, p->enabled());
132231200Smm  }
133231200Smm  assert(index == -1, "length does not match list");
134231200Smm}
135231200Smm
136228753Smminline JavaAssertions::OptionList*
137228753SmmJavaAssertions::match_class(const char* classname) {
138228753Smm  for (OptionList* p = _classes; p != 0; p = p->next()) {
139248616Smm    if (strcmp(p->name(), classname) == 0) {
140228753Smm      return p;
141228753Smm    }
142228753Smm  }
143228753Smm  return 0;
144228753Smm}
145228753Smm
146228753SmmJavaAssertions::OptionList*
147228753SmmJavaAssertions::match_package(const char* classname) {
148248616Smm  // Search the package list for any items that apply to classname.  Each
149228753Smm  // sub-package in classname is checked, from most-specific to least, until one
150228753Smm  // is found.
151228753Smm  if (_packages == 0) return 0;
152228753Smm
153231200Smm  // Find the length of the "most-specific" package in classname.  If classname
154228753Smm  // does not include a package, length will be 0 which will match items for the
155231200Smm  // default package (from options "-ea:..."  or "-da:...").
156228753Smm  size_t len = strlen(classname);
157231200Smm  for (/* empty */; len > 0 && classname[len] != '/'; --len) /* empty */;
158231200Smm
159231200Smm  do {
160231200Smm    assert(len == 0 || classname[len] == '/', "not a package name");
161231200Smm    for (OptionList* p = _packages; p != 0; p = p->next()) {
162231200Smm      if (strncmp(p->name(), classname, len) == 0 && p->name()[len] == '\0') {
163231200Smm        return p;
164228753Smm      }
165231200Smm    }
166228753Smm
167231200Smm    // Find the length of the next package, taking care to avoid decrementing
168231200Smm    // past 0 (len is unsigned).
169231200Smm    while (len > 0 && classname[--len] != '/') /* empty */;
170231200Smm  } while (len > 0);
171228753Smm
172228753Smm  return 0;
173228753Smm}
174248616Smm
175228753Smminline void JavaAssertions::trace(const char* name,
176228753Smmconst char* typefound, const char* namefound, bool enabled) {
177228753Smm  if (TraceJavaAssertions) {
178228753Smm    tty->print_cr("JavaAssertions:  search for %s found %s %s=%d",
179228753Smm      name, typefound, namefound[0] != '\0' ? namefound : "'default'", enabled);
180228753Smm  }
181228753Smm}
182228753Smm
183228753Smmbool JavaAssertions::enabled(const char* classname, bool systemClass) {
184228753Smm  assert(classname != 0, "must have a classname");
185248616Smm
186228753Smm  // This will be slow if the number of assertion options on the command line is
187228753Smm  // large--it traverses two lists, one of them multiple times.  Could use a
188228753Smm  // single n-ary tree instead of lists if someone ever notices.
189228753Smm
190231200Smm  // First check options that apply to classes.  If we find a match we're done.
191231200Smm  OptionList* p;
192231200Smm  if (p = match_class(classname)) {
193231200Smm    trace(classname, "class", p->name(), p->enabled());
194231200Smm    return p->enabled();
195231200Smm  }
196231200Smm
197231200Smm  // Now check packages, from most specific to least.
198231200Smm  if (p = match_package(classname)) {
199231200Smm    trace(classname, "package", p->name(), p->enabled());
200231200Smm    return p->enabled();
201231200Smm  }
202231200Smm
203231200Smm  // No match.  Return the default status.
204231200Smm  bool result = systemClass ? systemClassDefault() : userClassDefault();
205231200Smm  trace(classname, systemClass ? "system" : "user", "default", result);
206231200Smm  return result;
207231200Smm}
208231200Smm