Path: blob/master/src/hotspot/share/compiler/compilerDirectives.cpp
64440 views
/*1* Copyright (c) 1998, 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 "ci/ciMethod.hpp"26#include "ci/ciUtilities.inline.hpp"27#include "compiler/abstractCompiler.hpp"28#include "compiler/compilerDirectives.hpp"29#include "compiler/compilerOracle.hpp"30#include "memory/allocation.inline.hpp"31#include "memory/resourceArea.hpp"32#include "runtime/globals_extension.hpp"3334CompilerDirectives::CompilerDirectives() : _next(NULL), _match(NULL), _ref_count(0) {35_c1_store = new DirectiveSet(this);36_c1_store->init_control_intrinsic();37_c2_store = new DirectiveSet(this);38_c2_store->init_control_intrinsic();39};4041CompilerDirectives::~CompilerDirectives() {42if (_c1_store != NULL) {43delete _c1_store;44}45if (_c2_store != NULL) {46delete _c2_store;47}4849// remove all linked method matchers50BasicMatcher* tmp = _match;51while (tmp != NULL) {52BasicMatcher* next = tmp->next();53delete tmp;54tmp = next;55}56}5758void CompilerDirectives::print(outputStream* st) {59assert(DirectivesStack_lock->owned_by_self(), "");60if (_match != NULL) {61st->cr();62st->print("Directive:");63if (is_default_directive()) {64st->print_cr(" (default)");65} else {66st->cr();67}68st->print(" matching: ");69_match->print(st);70BasicMatcher* tmp = _match->next();71while (tmp != NULL) {72st->print(", ");73tmp->print(st);74tmp = tmp->next();75}76st->cr();77} else {78assert(0, "There should always be a match");79}8081if (_c1_store != NULL) {82st->print_cr(" c1 directives:");83_c1_store->print(st);84}85if (_c2_store != NULL) {86st->cr();87st->print_cr(" c2 directives:");88_c2_store->print(st);89}90//---91}9293void CompilerDirectives::finalize(outputStream* st) {94if (_c1_store != NULL) {95_c1_store->finalize(st);96}97if (_c2_store != NULL) {98_c2_store->finalize(st);99}100}101102void DirectiveSet::finalize(outputStream* st) {103// Check LogOption and warn104if (LogOption && !LogCompilation) {105st->print_cr("Warning: +LogCompilation must be set to enable compilation logging from directives");106}107if (PrintAssemblyOption && FLAG_IS_DEFAULT(DebugNonSafepoints)) {108warning("printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output");109DebugNonSafepoints = true;110}111112// if any flag has been modified - set directive as enabled113// unless it already has been explicitly set.114if (!_modified[EnableIndex]) {115if (_inlinematchers != NULL) {116EnableOption = true;117return;118}119int i;120for (i = 0; i < number_of_flags; i++) {121if (_modified[i]) {122EnableOption = true;123return;124}125}126}127}128129CompilerDirectives* CompilerDirectives::next() {130return _next;131}132133bool CompilerDirectives::match(const methodHandle& method) {134if (is_default_directive()) {135return true;136}137if (method == NULL) {138return false;139}140if (_match->match(method)) {141return true;142}143return false;144}145146bool CompilerDirectives::add_match(char* str, const char*& error_msg) {147BasicMatcher* bm = BasicMatcher::parse_method_pattern(str, error_msg, false);148if (bm == NULL) {149assert(error_msg != NULL, "Must have error message");150return false;151} else {152bm->set_next(_match);153_match = bm;154return true;155}156}157158void CompilerDirectives::inc_refcount() {159assert(DirectivesStack_lock->owned_by_self(), "");160_ref_count++;161}162163void CompilerDirectives::dec_refcount() {164assert(DirectivesStack_lock->owned_by_self(), "");165_ref_count--;166}167168int CompilerDirectives::refcount() {169assert(DirectivesStack_lock->owned_by_self(), "");170return _ref_count;171}172173DirectiveSet* CompilerDirectives::get_for(AbstractCompiler *comp) {174assert(DirectivesStack_lock->owned_by_self(), "");175if (comp == NULL) { // Xint176return _c1_store;177} else if (comp->is_c2()) {178return _c2_store;179} else {180// use c1_store as default181assert(comp->is_c1() || comp->is_jvmci(), "");182return _c1_store;183}184}185186// In the list of Control/disabled intrinsics, the ID of the control intrinsics can separated:187// - by ',' (if -XX:Control/DisableIntrinsic is used once when invoking the VM) or188// - by '\n' (if -XX:Control/DisableIntrinsic is used multiple times when invoking the VM) or189// - by ' ' (if Control/DisableIntrinsic is used on a per-method level, e.g., with CompileCommand).190//191// To simplify the processing of the list, the canonicalize_control_intrinsic() method192// returns a new copy of the list in which '\n' and ' ' is replaced with ','.193ccstrlist DirectiveSet::canonicalize_control_intrinsic(ccstrlist option_value) {194char* canonicalized_list = NEW_C_HEAP_ARRAY(char, strlen(option_value) + 1, mtCompiler);195int i = 0;196char current;197while ((current = option_value[i]) != '\0') {198if (current == '\n' || current == ' ') {199canonicalized_list[i] = ',';200} else {201canonicalized_list[i] = current;202}203i++;204}205canonicalized_list[i] = '\0';206return canonicalized_list;207}208209ControlIntrinsicIter::ControlIntrinsicIter(ccstrlist option_value, bool disable_all)210: _disableIntrinsic(disable_all) {211_list = (char*)DirectiveSet::canonicalize_control_intrinsic(option_value);212_saved_ptr = _list;213_enabled = false;214215_token = strtok_r(_saved_ptr, ",", &_saved_ptr);216next_token();217}218219ControlIntrinsicIter::~ControlIntrinsicIter() {220FREE_C_HEAP_ARRAY(char, _list);221}222223// pre-increment224ControlIntrinsicIter& ControlIntrinsicIter::operator++() {225_token = strtok_r(NULL, ",", &_saved_ptr);226next_token();227return *this;228}229230void ControlIntrinsicIter::next_token() {231if (_token && !_disableIntrinsic) {232char ch = _token[0];233234if (ch != '+' && ch != '-') {235warning("failed to parse %s. must start with +/-!", _token);236} else {237_enabled = ch == '+';238_token++;239}240}241}242243void DirectiveSet::init_control_intrinsic() {244for (ControlIntrinsicIter iter(ControlIntrinsic); *iter != NULL; ++iter) {245vmIntrinsics::ID id = vmIntrinsics::find_id(*iter);246247if (id != vmIntrinsics::_none) {248_intrinsic_control_words[vmIntrinsics::as_int(id)] = iter.is_enabled();249}250}251252// Order matters, DisableIntrinsic can overwrite ControlIntrinsic253for (ControlIntrinsicIter iter(DisableIntrinsic, true/*disable_all*/); *iter != NULL; ++iter) {254vmIntrinsics::ID id = vmIntrinsics::find_id(*iter);255256if (id != vmIntrinsics::_none) {257_intrinsic_control_words[vmIntrinsics::as_int(id)] = false;258}259}260}261262DirectiveSet::DirectiveSet(CompilerDirectives* d) :_inlinematchers(NULL), _directive(d) {263#define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue;264compilerdirectives_common_flags(init_defaults_definition)265compilerdirectives_c2_flags(init_defaults_definition)266compilerdirectives_c1_flags(init_defaults_definition)267memset(_modified, 0, sizeof(_modified));268_intrinsic_control_words.fill_in(/*default value*/TriBool());269}270271DirectiveSet::~DirectiveSet() {272// remove all linked methodmatchers273InlineMatcher* tmp = _inlinematchers;274while (tmp != NULL) {275InlineMatcher* next = tmp->next();276delete tmp;277tmp = next;278}279}280281// A smart pointer of DirectiveSet. It uses Copy-on-Write strategy to avoid cloning.282// It provides 2 accesses of the underlying raw pointer.283// 1) operator->() returns a pointer to a constant DirectiveSet. It's read-only.284// 2) cloned() returns a pointer that points to the cloned DirectiveSet.285// Users should only use cloned() when they need to update DirectiveSet.286//287// In the end, users need to invoke commit() to finalize the pending changes.288// If cloning happens, the smart pointer will return the new pointer after releasing the original289// one on DirectivesStack. If cloning doesn't happen, it returns the original intact pointer.290class DirectiveSetPtr {291private:292DirectiveSet* _origin;293DirectiveSet* _clone;294NONCOPYABLE(DirectiveSetPtr);295296public:297DirectiveSetPtr(DirectiveSet* origin): _origin(origin), _clone(nullptr) {298assert(origin != nullptr, "DirectiveSetPtr cannot be initialized with a NULL pointer.");299}300301DirectiveSet const* operator->() {302return (_clone == nullptr) ? _origin : _clone;303}304305DirectiveSet* cloned() {306if (_clone == nullptr) {307_clone = DirectiveSet::clone(_origin);308}309return _clone;310}311312DirectiveSet* commit() {313if (_clone != nullptr) {314// We are returning a (parentless) copy. The originals parent don't need to account for this.315DirectivesStack::release(_origin);316_origin = _clone;317_clone = nullptr;318}319320return _origin;321}322};323324// Backward compatibility for CompileCommands325// Breaks the abstraction and causes lots of extra complexity326// - if some option is changed we need to copy directiveset since it no longer can be shared327// - Need to free copy after use328// - Requires a modified bit so we don't overwrite options that is set by directives329DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle& method) {330// Early bail out - checking all options is expensive - we rely on them not being used331// Only set a flag if it has not been modified and value changes.332// Only copy set if a flag needs to be set333if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::has_any_command_set()) {334DirectiveSetPtr set(this);335336#ifdef COMPILER1337if (C1Breakpoint) {338// If the directives didn't have 'BreakAtExecute',339// the command 'C1Breakpoint' would become effective.340if (!_modified[BreakAtExecuteIndex]) {341set.cloned()->BreakAtExecuteOption = true;342}343}344#endif345346// All CompileCommands are not equal so this gets a bit verbose347// When CompileCommands have been refactored less clutter will remain.348if (CompilerOracle::should_break_at(method)) {349// If the directives didn't have 'BreakAtCompile' or 'BreakAtExecute',350// the sub-command 'Break' of the 'CompileCommand' would become effective.351if (!_modified[BreakAtCompileIndex]) {352set.cloned()->BreakAtCompileOption = true;353}354if (!_modified[BreakAtExecuteIndex]) {355set.cloned()->BreakAtExecuteOption = true;356}357}358if (!_modified[LogIndex]) {359bool log = CompilerOracle::should_log(method);360if (log != set->LogOption) {361set.cloned()->LogOption = log;362}363}364365if (CompilerOracle::should_print(method)) {366if (!_modified[PrintAssemblyIndex]) {367set.cloned()->PrintAssemblyOption = true;368}369}370// Exclude as in should not compile == Enabled371if (CompilerOracle::should_exclude(method)) {372if (!_modified[ExcludeIndex]) {373set.cloned()->ExcludeOption = true;374}375}376377// inline and dontinline (including exclude) are implemented in the directiveset accessors378#define init_default_cc(name, type, dvalue, cc_flag) { type v; if (!_modified[name##Index] && CompileCommand::cc_flag != CompileCommand::Unknown && CompilerOracle::has_option_value(method, CompileCommand::cc_flag, v) && v != this->name##Option) { set.cloned()->name##Option = v; } }379compilerdirectives_common_flags(init_default_cc)380compilerdirectives_c2_flags(init_default_cc)381compilerdirectives_c1_flags(init_default_cc)382383// Canonicalize DisableIntrinsic to contain only ',' as a separator.384ccstrlist option_value;385bool need_reset = true; // if Control/DisableIntrinsic redefined, only need to reset control_words once386387if (!_modified[ControlIntrinsicIndex] &&388CompilerOracle::has_option_value(method, CompileCommand::ControlIntrinsic, option_value)) {389ControlIntrinsicIter iter(option_value);390391if (need_reset) {392set.cloned()->_intrinsic_control_words.fill_in(TriBool());393need_reset = false;394}395396while (*iter != NULL) {397vmIntrinsics::ID id = vmIntrinsics::find_id(*iter);398if (id != vmIntrinsics::_none) {399set.cloned()->_intrinsic_control_words[vmIntrinsics::as_int(id)] = iter.is_enabled();400}401402++iter;403}404}405406407if (!_modified[DisableIntrinsicIndex] &&408CompilerOracle::has_option_value(method, CompileCommand::DisableIntrinsic, option_value)) {409ControlIntrinsicIter iter(option_value, true/*disable_all*/);410411if (need_reset) {412set.cloned()->_intrinsic_control_words.fill_in(TriBool());413need_reset = false;414}415416while (*iter != NULL) {417vmIntrinsics::ID id = vmIntrinsics::find_id(*iter);418if (id != vmIntrinsics::_none) {419set.cloned()->_intrinsic_control_words[vmIntrinsics::as_int(id)] = false;420}421422++iter;423}424}425426return set.commit();427}428// Nothing changed429return this;430}431432CompilerDirectives* DirectiveSet::directive() {433assert(_directive != NULL, "Must have been initialized");434return _directive;435}436437bool DirectiveSet::matches_inline(const methodHandle& method, int inline_action) {438if (_inlinematchers != NULL) {439if (_inlinematchers->match(method, inline_action)) {440return true;441}442}443return false;444}445446bool DirectiveSet::should_inline(ciMethod* inlinee) {447inlinee->check_is_loaded();448VM_ENTRY_MARK;449methodHandle mh(THREAD, inlinee->get_Method());450451if (_inlinematchers != NULL) {452return matches_inline(mh, InlineMatcher::force_inline);453}454if (!CompilerDirectivesIgnoreCompileCommandsOption) {455return CompilerOracle::should_inline(mh);456}457return false;458}459460bool DirectiveSet::should_not_inline(ciMethod* inlinee) {461inlinee->check_is_loaded();462VM_ENTRY_MARK;463methodHandle mh(THREAD, inlinee->get_Method());464465if (_inlinematchers != NULL) {466return matches_inline(mh, InlineMatcher::dont_inline);467}468if (!CompilerDirectivesIgnoreCompileCommandsOption) {469return CompilerOracle::should_not_inline(mh);470}471return false;472}473474bool DirectiveSet::parse_and_add_inline(char* str, const char*& error_msg) {475InlineMatcher* m = InlineMatcher::parse_inline_pattern(str, error_msg);476if (m != NULL) {477// add matcher last in chain - the order is significant478append_inline(m);479return true;480} else {481assert(error_msg != NULL, "Error message must be set");482return false;483}484}485486void DirectiveSet::append_inline(InlineMatcher* m) {487if (_inlinematchers == NULL) {488_inlinematchers = m;489return;490}491InlineMatcher* tmp = _inlinematchers;492while (tmp->next() != NULL) {493tmp = tmp->next();494}495tmp->set_next(m);496}497498void DirectiveSet::print_inline(outputStream* st) {499if (_inlinematchers == NULL) {500st->print_cr(" inline: -");501} else {502st->print(" inline: ");503_inlinematchers->print(st);504InlineMatcher* tmp = _inlinematchers->next();505while (tmp != NULL) {506st->print(", ");507tmp->print(st);508tmp = tmp->next();509}510st->cr();511}512}513514bool DirectiveSet::is_intrinsic_disabled(const methodHandle& method) {515vmIntrinsics::ID id = method->intrinsic_id();516assert(id > vmIntrinsics::_none && id < vmIntrinsics::ID_LIMIT, "invalid intrinsic_id!");517518TriBool b = _intrinsic_control_words[vmIntrinsics::as_int(id)];519if (b.is_default()) {520return false; // if unset, every intrinsic is enabled.521} else {522return !b;523}524}525526DirectiveSet* DirectiveSet::clone(DirectiveSet const* src) {527DirectiveSet* set = new DirectiveSet(NULL);528// Ordinary allocations of DirectiveSet would call init_control_intrinsic()529// immediately to create a new copy for set->Control/DisableIntrinsicOption.530// However, here it does not need to because the code below creates531// a copy of src->Control/DisableIntrinsicOption that initializes532// set->Control/DisableIntrinsicOption.533534memcpy(set->_modified, src->_modified, sizeof(src->_modified));535536InlineMatcher* tmp = src->_inlinematchers;537while (tmp != NULL) {538set->append_inline(tmp->clone());539tmp = tmp->next();540}541542#define copy_members_definition(name, type, dvalue, cc_flag) set->name##Option = src->name##Option;543compilerdirectives_common_flags(copy_members_definition)544compilerdirectives_c2_flags(copy_members_definition)545compilerdirectives_c1_flags(copy_members_definition)546547set->_intrinsic_control_words = src->_intrinsic_control_words;548return set;549}550551// Create a new dirstack and push a default directive552void DirectivesStack::init() {553CompilerDirectives* _default_directives = new CompilerDirectives();554char str[] = "*.*";555const char* error_msg = NULL;556_default_directives->add_match(str, error_msg);557#if defined(COMPILER1) || INCLUDE_JVMCI558_default_directives->_c1_store->EnableOption = true;559#endif560#ifdef COMPILER2561if (CompilerConfig::is_c2_enabled()) {562_default_directives->_c2_store->EnableOption = true;563}564#endif565assert(error_msg == NULL, "Must succeed.");566push(_default_directives);567}568569DirectiveSet* DirectivesStack::getDefaultDirective(AbstractCompiler* comp) {570MutexLocker locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);571572assert(_bottom != NULL, "Must never be empty");573_bottom->inc_refcount();574return _bottom->get_for(comp);575}576577void DirectivesStack::push(CompilerDirectives* directive) {578MutexLocker locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);579580directive->inc_refcount();581if (_top == NULL) {582assert(_bottom == NULL, "There can only be one default directive");583_bottom = directive; // default directive, can never be removed.584}585586directive->set_next(_top);587_top = directive;588_depth++;589}590591void DirectivesStack::pop(int count) {592MutexLocker locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);593assert(count > -1, "No negative values");594for (int i = 0; i < count; i++) {595pop_inner();596}597}598599void DirectivesStack::pop_inner() {600assert(DirectivesStack_lock->owned_by_self(), "");601602if (_top->next() == NULL) {603return; // Do nothing - don't allow an empty stack604}605CompilerDirectives* tmp = _top;606_top = _top->next();607_depth--;608609DirectivesStack::release(tmp);610}611612bool DirectivesStack::check_capacity(int request_size, outputStream* st) {613if ((request_size + _depth) > CompilerDirectivesLimit) {614st->print_cr("Could not add %i more directives. Currently %i/%i directives.", request_size, _depth, CompilerDirectivesLimit);615return false;616}617return true;618}619620void DirectivesStack::clear() {621// holding the lock during the whole operation ensuring consistent result622MutexLocker locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);623while (_top->next() != NULL) {624pop_inner();625}626}627628void DirectivesStack::print(outputStream* st) {629MutexLocker locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);630CompilerDirectives* tmp = _top;631while (tmp != NULL) {632tmp->print(st);633tmp = tmp->next();634st->cr();635}636}637638void DirectivesStack::release(DirectiveSet* set) {639assert(set != NULL, "Never NULL");640MutexLocker locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);641if (set->is_exclusive_copy()) {642// Old CompilecCmmands forced us to create an exclusive copy643delete set;644} else {645assert(set->directive() != NULL, "Never NULL");646release(set->directive());647}648}649650651void DirectivesStack::release(CompilerDirectives* dir) {652assert(DirectivesStack_lock->owned_by_self(), "");653dir->dec_refcount();654if (dir->refcount() == 0) {655delete dir;656}657}658659DirectiveSet* DirectivesStack::getMatchingDirective(const methodHandle& method, AbstractCompiler *comp) {660assert(_depth > 0, "Must never be empty");661662DirectiveSet* match = NULL;663{664MutexLocker locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);665666CompilerDirectives* dir = _top;667assert(dir != NULL, "Must be initialized");668669while (dir != NULL) {670if (dir->is_default_directive() || dir->match(method)) {671match = dir->get_for(comp);672assert(match != NULL, "Consistency");673if (match->EnableOption) {674// The directiveSet for this compile is also enabled -> success675dir->inc_refcount();676break;677}678}679dir = dir->next();680}681}682guarantee(match != NULL, "There should always be a default directive that matches");683684// Check for legacy compile commands update, without DirectivesStack_lock685return match->compilecommand_compatibility_init(method);686}687688689