duke@435: /* coleenp@4037: * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #include "precompiled.hpp" stefank@2314: #include "classfile/javaAssertions.hpp" stefank@2314: #include "classfile/javaClasses.hpp" stefank@2314: #include "classfile/systemDictionary.hpp" stefank@2314: #include "classfile/vmSymbols.hpp" stefank@2314: #include "memory/allocation.inline.hpp" stefank@2314: #include "memory/oopFactory.hpp" stefank@2314: #include "oops/oop.inline.hpp" stefank@2314: #include "runtime/handles.inline.hpp" duke@435: duke@435: bool JavaAssertions::_userDefault = false; duke@435: bool JavaAssertions::_sysDefault = false; duke@435: JavaAssertions::OptionList* JavaAssertions::_classes = 0; duke@435: JavaAssertions::OptionList* JavaAssertions::_packages = 0; duke@435: duke@435: JavaAssertions::OptionList::OptionList(const char* name, bool enabled, duke@435: OptionList* next) { duke@435: assert(name != 0, "need a name"); duke@435: _name = name; duke@435: _enabled = enabled; duke@435: _next = next; duke@435: } duke@435: duke@435: int JavaAssertions::OptionList::count(OptionList* p) { duke@435: int rc; duke@435: for (rc = 0; p != 0; p = p->next(), ++rc) /* empty */; duke@435: return rc; duke@435: } duke@435: duke@435: void JavaAssertions::addOption(const char* name, bool enable) { duke@435: assert(name != 0, "must have a name"); duke@435: duke@435: // Copy the name. The storage needs to exist for the the lifetime of the vm; duke@435: // it is never freed, so will be leaked (along with other option strings - duke@435: // e.g., bootclasspath) if a process creates/destroys multiple VMs. duke@435: int len = (int)strlen(name); zgu@3900: char *name_copy = NEW_C_HEAP_ARRAY(char, len + 1, mtClass); duke@435: strcpy(name_copy, name); duke@435: duke@435: // Figure out which list the new item should go on. Names that end in "..." duke@435: // go on the package tree list. duke@435: OptionList** head = &_classes; duke@435: if (len >= 3 && strcmp(name_copy + len - 3, "...") == 0) { duke@435: // Delete the "...". duke@435: len -= 3; duke@435: name_copy[len] = '\0'; duke@435: head = &_packages; duke@435: } duke@435: duke@435: // Convert class/package names to internal format. Will have to convert back duke@435: // when copying to java in createJavaAssertionStatusDirectives, but that duke@435: // should happen only once. Alternative would require that duke@435: // JVM_DesiredAssertionStatus pass the external_name() to duke@435: // JavaAssertion::enabled(), but that is done once per loaded class. duke@435: for (int i = 0; i < len; ++i) { duke@435: if (name_copy[i] == '.') name_copy[i] = '/'; duke@435: } duke@435: duke@435: if (TraceJavaAssertions) { duke@435: tty->print_cr("JavaAssertions: adding %s %s=%d", duke@435: head == &_classes ? "class" : "package", duke@435: name_copy[0] != '\0' ? name_copy : "'default'", duke@435: enable); duke@435: } duke@435: duke@435: // Prepend a new item to the list. Items added later take precedence, so duke@435: // prepending allows us to stop searching the list after the first match. duke@435: *head = new OptionList(name_copy, enable, *head); duke@435: } duke@435: duke@435: oop JavaAssertions::createAssertionStatusDirectives(TRAPS) { coleenp@2497: Symbol* asd_sym = vmSymbols::java_lang_AssertionStatusDirectives(); coleenp@4037: Klass* k = SystemDictionary::resolve_or_fail(asd_sym, true, CHECK_NULL); duke@435: instanceKlassHandle asd_klass (THREAD, k); duke@435: asd_klass->initialize(CHECK_NULL); duke@435: Handle h = asd_klass->allocate_instance_handle(CHECK_NULL); duke@435: duke@435: int len; duke@435: typeArrayOop t; duke@435: len = OptionList::count(_packages); never@1577: objArrayOop pn = oopFactory::new_objArray(SystemDictionary::String_klass(), len, CHECK_NULL); duke@435: objArrayHandle pkgNames (THREAD, pn); duke@435: t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL); duke@435: typeArrayHandle pkgEnabled(THREAD, t); duke@435: fillJavaArrays(_packages, len, pkgNames, pkgEnabled, CHECK_NULL); duke@435: duke@435: len = OptionList::count(_classes); never@1577: objArrayOop cn = oopFactory::new_objArray(SystemDictionary::String_klass(), len, CHECK_NULL); duke@435: objArrayHandle classNames (THREAD, cn); duke@435: t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL); duke@435: typeArrayHandle classEnabled(THREAD, t); duke@435: fillJavaArrays(_classes, len, classNames, classEnabled, CHECK_NULL); duke@435: duke@435: java_lang_AssertionStatusDirectives::set_packages(h(), pkgNames()); duke@435: java_lang_AssertionStatusDirectives::set_packageEnabled(h(), pkgEnabled()); duke@435: java_lang_AssertionStatusDirectives::set_classes(h(), classNames()); duke@435: java_lang_AssertionStatusDirectives::set_classEnabled(h(), classEnabled()); duke@435: java_lang_AssertionStatusDirectives::set_deflt(h(), userClassDefault()); duke@435: return h(); duke@435: } duke@435: duke@435: void JavaAssertions::fillJavaArrays(const OptionList* p, int len, duke@435: objArrayHandle names, typeArrayHandle enabled, TRAPS) { duke@435: // Fill in the parallel names and enabled (boolean) arrays. Start at the end duke@435: // of the array and work backwards, so the order of items in the arrays duke@435: // matches the order on the command line (the list is in reverse order, since duke@435: // it was created by prepending successive items from the command line). duke@435: int index; duke@435: for (index = len - 1; p != 0; p = p->next(), --index) { duke@435: assert(index >= 0, "length does not match list"); duke@435: Handle s = java_lang_String::create_from_str(p->name(), CHECK); duke@435: s = java_lang_String::char_converter(s, '/', '.', CHECK); duke@435: names->obj_at_put(index, s()); duke@435: enabled->bool_at_put(index, p->enabled()); duke@435: } duke@435: assert(index == -1, "length does not match list"); duke@435: } duke@435: duke@435: inline JavaAssertions::OptionList* duke@435: JavaAssertions::match_class(const char* classname) { duke@435: for (OptionList* p = _classes; p != 0; p = p->next()) { duke@435: if (strcmp(p->name(), classname) == 0) { duke@435: return p; duke@435: } duke@435: } duke@435: return 0; duke@435: } duke@435: duke@435: JavaAssertions::OptionList* duke@435: JavaAssertions::match_package(const char* classname) { duke@435: // Search the package list for any items that apply to classname. Each duke@435: // sub-package in classname is checked, from most-specific to least, until one duke@435: // is found. duke@435: if (_packages == 0) return 0; duke@435: duke@435: // Find the length of the "most-specific" package in classname. If classname duke@435: // does not include a package, length will be 0 which will match items for the duke@435: // default package (from options "-ea:..." or "-da:..."). duke@435: size_t len = strlen(classname); duke@435: for (/* empty */; len > 0 && classname[len] != '/'; --len) /* empty */; duke@435: duke@435: do { duke@435: assert(len == 0 || classname[len] == '/', "not a package name"); duke@435: for (OptionList* p = _packages; p != 0; p = p->next()) { duke@435: if (strncmp(p->name(), classname, len) == 0 && p->name()[len] == '\0') { duke@435: return p; duke@435: } duke@435: } duke@435: duke@435: // Find the length of the next package, taking care to avoid decrementing duke@435: // past 0 (len is unsigned). duke@435: while (len > 0 && classname[--len] != '/') /* empty */; duke@435: } while (len > 0); duke@435: duke@435: return 0; duke@435: } duke@435: duke@435: inline void JavaAssertions::trace(const char* name, duke@435: const char* typefound, const char* namefound, bool enabled) { duke@435: if (TraceJavaAssertions) { duke@435: tty->print_cr("JavaAssertions: search for %s found %s %s=%d", duke@435: name, typefound, namefound[0] != '\0' ? namefound : "'default'", enabled); duke@435: } duke@435: } duke@435: duke@435: bool JavaAssertions::enabled(const char* classname, bool systemClass) { duke@435: assert(classname != 0, "must have a classname"); duke@435: duke@435: // This will be slow if the number of assertion options on the command line is duke@435: // large--it traverses two lists, one of them multiple times. Could use a duke@435: // single n-ary tree instead of lists if someone ever notices. duke@435: duke@435: // First check options that apply to classes. If we find a match we're done. duke@435: OptionList* p; duke@435: if (p = match_class(classname)) { duke@435: trace(classname, "class", p->name(), p->enabled()); duke@435: return p->enabled(); duke@435: } duke@435: duke@435: // Now check packages, from most specific to least. duke@435: if (p = match_package(classname)) { duke@435: trace(classname, "package", p->name(), p->enabled()); duke@435: return p->enabled(); duke@435: } duke@435: duke@435: // No match. Return the default status. duke@435: bool result = systemClass ? systemClassDefault() : userClassDefault(); duke@435: trace(classname, systemClass ? "system" : "user", "default", result); duke@435: return result; duke@435: }