Path: blob/master/src/hotspot/share/classfile/javaAssertions.cpp
40949 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "classfile/javaAssertions.hpp"26#include "classfile/javaClasses.hpp"27#include "classfile/systemDictionary.hpp"28#include "classfile/vmClasses.hpp"29#include "classfile/vmSymbols.hpp"30#include "memory/allocation.inline.hpp"31#include "memory/oopFactory.hpp"32#include "oops/objArrayOop.inline.hpp"33#include "oops/oop.inline.hpp"34#include "oops/typeArrayOop.inline.hpp"35#include "runtime/handles.inline.hpp"3637bool JavaAssertions::_userDefault = false;38bool JavaAssertions::_sysDefault = false;39JavaAssertions::OptionList* JavaAssertions::_classes = 0;40JavaAssertions::OptionList* JavaAssertions::_packages = 0;4142JavaAssertions::OptionList::OptionList(const char* name, bool enabled,43OptionList* next) {44assert(name != 0, "need a name");45_name = name;46_enabled = enabled;47_next = next;48}4950int JavaAssertions::OptionList::count(OptionList* p) {51int rc;52for (rc = 0; p != 0; p = p->next(), ++rc) /* empty */;53return rc;54}5556void JavaAssertions::addOption(const char* name, bool enable) {57assert(name != 0, "must have a name");5859// Copy the name. The storage needs to exist for the the lifetime of the vm;60// it is never freed, so will be leaked (along with other option strings -61// e.g., bootclasspath) if a process creates/destroys multiple VMs.62int len = (int)strlen(name);63char *name_copy = NEW_C_HEAP_ARRAY(char, len + 1, mtClass);64strcpy(name_copy, name);6566// Figure out which list the new item should go on. Names that end in "..."67// go on the package tree list.68OptionList** head = &_classes;69if (len >= 3 && strcmp(name_copy + len - 3, "...") == 0) {70// Delete the "...".71len -= 3;72name_copy[len] = '\0';73head = &_packages;74}7576// Convert class/package names to internal format. Will have to convert back77// when copying to java in createJavaAssertionStatusDirectives, but that78// should happen only once. Alternative would require that79// JVM_DesiredAssertionStatus pass the external_name() to80// JavaAssertion::enabled(), but that is done once per loaded class.81for (int i = 0; i < len; ++i) {82if (name_copy[i] == JVM_SIGNATURE_DOT) name_copy[i] = JVM_SIGNATURE_SLASH;83}8485if (TraceJavaAssertions) {86tty->print_cr("JavaAssertions: adding %s %s=%d",87head == &_classes ? "class" : "package",88name_copy[0] != '\0' ? name_copy : "'default'",89enable);90}9192// Prepend a new item to the list. Items added later take precedence, so93// prepending allows us to stop searching the list after the first match.94*head = new OptionList(name_copy, enable, *head);95}9697oop JavaAssertions::createAssertionStatusDirectives(TRAPS) {98Symbol* asd_sym = vmSymbols::java_lang_AssertionStatusDirectives();99Klass* k = SystemDictionary::resolve_or_fail(asd_sym, true, CHECK_NULL);100InstanceKlass* asd_klass = InstanceKlass::cast(k);101asd_klass->initialize(CHECK_NULL);102Handle h = asd_klass->allocate_instance_handle(CHECK_NULL);103104int len;105typeArrayOop t;106len = OptionList::count(_packages);107objArrayOop pn = oopFactory::new_objArray(vmClasses::String_klass(), len, CHECK_NULL);108objArrayHandle pkgNames (THREAD, pn);109t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL);110typeArrayHandle pkgEnabled(THREAD, t);111fillJavaArrays(_packages, len, pkgNames, pkgEnabled, CHECK_NULL);112113len = OptionList::count(_classes);114objArrayOop cn = oopFactory::new_objArray(vmClasses::String_klass(), len, CHECK_NULL);115objArrayHandle classNames (THREAD, cn);116t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL);117typeArrayHandle classEnabled(THREAD, t);118fillJavaArrays(_classes, len, classNames, classEnabled, CHECK_NULL);119120java_lang_AssertionStatusDirectives::set_packages(h(), pkgNames());121java_lang_AssertionStatusDirectives::set_packageEnabled(h(), pkgEnabled());122java_lang_AssertionStatusDirectives::set_classes(h(), classNames());123java_lang_AssertionStatusDirectives::set_classEnabled(h(), classEnabled());124java_lang_AssertionStatusDirectives::set_deflt(h(), userClassDefault());125return h();126}127128void JavaAssertions::fillJavaArrays(const OptionList* p, int len,129objArrayHandle names, typeArrayHandle enabled, TRAPS) {130// Fill in the parallel names and enabled (boolean) arrays. Start at the end131// of the array and work backwards, so the order of items in the arrays132// matches the order on the command line (the list is in reverse order, since133// it was created by prepending successive items from the command line).134int index;135for (index = len - 1; p != 0; p = p->next(), --index) {136assert(index >= 0, "length does not match list");137Handle s = java_lang_String::create_from_str(p->name(), CHECK);138s = java_lang_String::char_converter(s, JVM_SIGNATURE_SLASH, JVM_SIGNATURE_DOT, CHECK);139names->obj_at_put(index, s());140enabled->bool_at_put(index, p->enabled());141}142assert(index == -1, "length does not match list");143}144145inline JavaAssertions::OptionList*146JavaAssertions::match_class(const char* classname) {147for (OptionList* p = _classes; p != 0; p = p->next()) {148if (strcmp(p->name(), classname) == 0) {149return p;150}151}152return 0;153}154155JavaAssertions::OptionList*156JavaAssertions::match_package(const char* classname) {157// Search the package list for any items that apply to classname. Each158// sub-package in classname is checked, from most-specific to least, until one159// is found.160if (_packages == 0) return 0;161162// Find the length of the "most-specific" package in classname. If classname163// does not include a package, length will be 0 which will match items for the164// default package (from options "-ea:..." or "-da:...").165size_t len = strlen(classname);166for (/* empty */; len > 0 && classname[len] != JVM_SIGNATURE_SLASH; --len) /* empty */;167168do {169assert(len == 0 || classname[len] == JVM_SIGNATURE_SLASH, "not a package name");170for (OptionList* p = _packages; p != 0; p = p->next()) {171if (strncmp(p->name(), classname, len) == 0 && p->name()[len] == '\0') {172return p;173}174}175176// Find the length of the next package, taking care to avoid decrementing177// past 0 (len is unsigned).178while (len > 0 && classname[--len] != JVM_SIGNATURE_SLASH) /* empty */;179} while (len > 0);180181return 0;182}183184inline void JavaAssertions::trace(const char* name,185const char* typefound, const char* namefound, bool enabled) {186if (TraceJavaAssertions) {187tty->print_cr("JavaAssertions: search for %s found %s %s=%d",188name, typefound, namefound[0] != '\0' ? namefound : "'default'", enabled);189}190}191192bool JavaAssertions::enabled(const char* classname, bool systemClass) {193assert(classname != 0, "must have a classname");194195// This will be slow if the number of assertion options on the command line is196// large--it traverses two lists, one of them multiple times. Could use a197// single n-ary tree instead of lists if someone ever notices.198199// First check options that apply to classes. If we find a match we're done.200OptionList* p;201if ((p = match_class(classname))) {202trace(classname, "class", p->name(), p->enabled());203return p->enabled();204}205206// Now check packages, from most specific to least.207if ((p = match_package(classname))) {208trace(classname, "package", p->name(), p->enabled());209return p->enabled();210}211212// No match. Return the default status.213bool result = systemClass ? systemClassDefault() : userClassDefault();214trace(classname, systemClass ? "system" : "user", "default", result);215return result;216}217218219