--- /dev/null 2015-09-21 09:36:40.397057507 +0200 +++ new/src/share/vm/compiler/compilerDirectives.cpp 2015-09-22 16:26:56.625641772 +0200 @@ -0,0 +1,338 @@ +/* + * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "ci/ciMethod.hpp" +#include "ci/ciUtilities.hpp" +#include "compiler/compilerDirectives.hpp" +#include "compiler/compilerOracle.hpp" + +CompilerDirectives::CompilerDirectives() :_match(NULL), _next(NULL), _ref_count(0) { + _c1_store = new DirectiveSet(this); + _c2_store = new DirectiveSet(this); +}; + +CompilerDirectives::~CompilerDirectives() { + if (_c1_store != NULL) { + delete _c1_store; + } + if (_c2_store != NULL) { + delete _c2_store; + } + + // remove all linked method matchers + BasicMatcher* tmp = _match; + while (tmp != NULL) { + BasicMatcher* next = tmp->next(); + delete tmp; + tmp = next; + } +} + +void CompilerDirectives::print(outputStream* st) { + st->cr(); + if (_match != NULL) { + st->print_cr("Directive:"); + st->print(" matching: "); + _match->print(st); + BasicMatcher* tmp = _match->next(); + while (tmp != NULL) { + st->print(", "); + tmp->print(st); + tmp = tmp->next(); + } + st->cr(); + } else { + assert(0, "There should always be a match"); + } + + if (_c1_store != NULL) { + st->print_cr(" c1 directives:"); + _c1_store->print(st); + } + if (_c2_store != NULL) { + st->print_cr(" c2 directives:"); + _c2_store->print(st); + } + //--- +} + +CompilerDirectives* CompilerDirectives::next() { + return _next; +} + +bool CompilerDirectives::match(methodHandle method, int comp_level) { + if (method == NULL) { + return false; + } + if (_match->match(method)) { + return true; + } + return false; +} + +bool CompilerDirectives::add_match(char* str, const char*& error_msg) { + int bytes_read; + + BasicMatcher* bm = BasicMatcher::parse_method_pattern(str, error_msg); + if (bm == NULL) { + assert(error_msg != NULL, "Must have error message"); + return false; + } else { + bm->set_next(_match); + _match = bm; + return true; + } +} + +void CompilerDirectives::inc_refcount() { + assert(DirectivesStack_lock->owned_by_self(), ""); + _ref_count++; +} + +void CompilerDirectives::dec_refcount() { + assert(DirectivesStack_lock->owned_by_self(), ""); + _ref_count--; + if (_ref_count == 0) { + delete this; + } +} + +DirectiveSet* CompilerDirectives::get_for(int comp_level) { + assert(DirectivesStack_lock->owned_by_self(), ""); + inc_refcount(); // The compiling thread is responsible to decrement this when finished. + assert((comp_level >= CompLevel_simple) && (comp_level <= CompLevel_full_optimization), "Outside bounds"); + if (comp_level == CompLevel_full_optimization) { + return _c2_store; + } else { + return _c1_store; + } +} + +DirectiveSet::DirectiveSet(CompilerDirectives* d) :_inlinematchers(NULL), _directive(d) { +#define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue; + compilerdirectives_common_flags(init_defaults_definition) + compilerdirectives_c2_flags(init_defaults_definition) + compilerdirectives_c1_flags(init_defaults_definition) + memset(_modified, 0, sizeof _modified); +} + +void DirectiveSet::release() { + MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); + directive()->dec_refcount(); +} + +DirectiveSet::~DirectiveSet() { + // remove all linked methodmatchers + InlineMatcher* tmp = _inlinematchers; + while (tmp != NULL) { + InlineMatcher* next = tmp->next(); + delete tmp; + tmp = next; + } + +#ifdef COMPILER2 + // Free if modified, otherwise it just points to the global vm flag value + if (_modified[DisableIntrinsicsIndex]) { + FREE_C_HEAP_ARRAY(char, (void *)this->DisableIntrinsicsOption); + } +#endif +} + +// Backward compatibility for CompileCommands +// Breaks the abstraction and causes lots of extra complexity +// - if some option is changed we need to copy dirset since it no longer can be shared +// - Need to free copy after use +// - Requires a modified bit so we don't overwrite options that is set by directives + +DirectiveSet* DirectiveSet::late_cc_init(methodHandle method) { + // Early bail out - checking all options is expensive - we rely on them not being used + // Only set a flag if it has not been modified and value changes. + // Only copy set if a flag needs to be set + if (CompileCommandCompatibilityOption && CompilerOracle::has_any_option()) { + DirectiveSet* set = clone(); + + bool changed = false; // Track if we actually change anything + + // All CompileCommands are not equal so this gets a bit verbose + // When CompileCommands have been refactored less clutter will remain. + if (CompilerOracle::should_break_at(method)) { + if (!_modified[BreakAtCompileIndex] && !set->BreakAtCompileOption) { + set->BreakAtCompileOption = true; + changed = true; + } + if (!_modified[BreakAtExecuteIndex] && !set->BreakAtExecuteOption) { + set->BreakAtExecuteOption = true; + changed = true; + } + } + if (CompilerOracle::should_log(method)) { + if (!_modified[LogIndex] && !set->LogOption) { + set->LogOption = true; + changed = true; + } + } + if (CompilerOracle::should_print(method)) { + if (!_modified[PrintAssemblyIndex] && !set->PrintAssemblyOption) { + set->PrintAssemblyOption = true; + changed = true; + } + } + // Exclude as in should not compile == Enabled + if (CompilerOracle::should_exclude(method)) { + if (!_modified[EnabledIndex] && !set->EnabledOption) { + set->EnabledOption = true; + changed = true; + } + } + + // inline and dontinline (including exclude) are implemented in the directiveset accessors +#define init_default_cc(name, type, dvalue, cc_flag) { type v; if (!_modified[name##Index] && CompilerOracle::has_option_value(method, #cc_flag, v) && v != this->name##Option) { this->name##Option = v; changed = true;} } + compilerdirectives_common_flags(init_default_cc) + compilerdirectives_c2_flags(init_default_cc) + compilerdirectives_c1_flags(init_default_cc) + + if (!changed) { + // We didn't actually update anything, discard. + delete set; + } else { + // We are returning a (parentless) copy. The originals parent don't need to account for this. + this->release(); + return set; + } + } + // Nothing changed + return this; +} + +CompilerDirectives* DirectiveSet::directive() { + assert(_directive != NULL, "Must have been initialized"); + return _directive; +} + +bool DirectiveSet::matches_inline(methodHandle method, int inline_action) { + if (_inlinematchers != NULL) { + if (_inlinematchers->match(method, InlineMatcher::force_inline)) { + return true; + } + } + return false; +} + +bool DirectiveSet::inline_commanded(ciMethod* inlinee) { + inlinee->check_is_loaded(); + VM_ENTRY_MARK; + methodHandle mh(THREAD, inlinee->get_Method()); + + if (matches_inline(mh, InlineMatcher::force_inline)) { + return true; + } + if (CompileCommandCompatibilityOption && CompilerOracle::should_inline(mh)) { + return true; + } + return false; +} + +bool DirectiveSet::dont_inline_commanded(ciMethod* inlinee) { + inlinee->check_is_loaded(); + VM_ENTRY_MARK; + methodHandle mh(THREAD, inlinee->get_Method()); + + if (matches_inline(mh, InlineMatcher::dont_inline)) { + return true; + } + if (CompileCommandCompatibilityOption && CompilerOracle::should_not_inline(mh)) { + return true; + } + return false; +} + +bool DirectiveSet::parse_and_add_inline(char* str, const char*& error_msg) { + InlineMatcher* m = InlineMatcher::parse_inline_pattern(str, error_msg); + if (m != NULL) { + // add matcher last in chain - the order is significant + append_inline(m); + return true; + } else { + assert(error_msg != NULL, "Error message must be set"); + return false; + } +} + +void DirectiveSet::append_inline(InlineMatcher* m) { + if (_inlinematchers == NULL) { + _inlinematchers = m; + return; + } + InlineMatcher* tmp = _inlinematchers; + while (tmp->next() != NULL) { + tmp = tmp->next(); + } + tmp->set_next(m); +} + +void DirectiveSet::print_inline(outputStream* st) { + if (_inlinematchers == NULL) { + st->print_cr(" inline: -"); + } else { + st->print(" inline: "); + _inlinematchers->print(st); + InlineMatcher* tmp = _inlinematchers->next(); + while (tmp != NULL) { + st->print(", "); + tmp->print(st); + tmp = tmp->next(); + } + st->cr(); + } +} + +bool DirectiveSet::is_intrinsic_disabled(methodHandle method) { + vmIntrinsics::ID id = method->intrinsic_id(); + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + + ccstr disable_intr = DisableIntrinsicsOption; + return ((disable_intr != '\0') && strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL); +} + +DirectiveSet* DirectiveSet::clone() { + DirectiveSet* set = clone(); + memcpy(set->_modified, _modified, sizeof(_modified)); + + InlineMatcher* tmp = _inlinematchers; + while (tmp != NULL) { + set->append_inline(tmp->clone()); + tmp = tmp->next(); + } + + #define copy_members_definition(name, type, dvalue, cc_flag) set->name##Option = name##Option; + compilerdirectives_common_flags(copy_members_definition) + compilerdirectives_c2_flags(copy_members_definition) + compilerdirectives_c1_flags(copy_members_definition) + + // Must duplicate str option + set->DisableIntrinsicsOption = os::strdup(DisableIntrinsicsOption, mtCompiler); + + return set; +}