Path: blob/master/src/hotspot/share/compiler/directivesParser.cpp
40930 views
/*1* Copyright (c) 2015, 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 "compiler/compileBroker.hpp"26#include "compiler/directivesParser.hpp"27#include "memory/allocation.inline.hpp"28#include "memory/resourceArea.hpp"29#include "runtime/os.hpp"30#include <string.h>3132void DirectivesParser::push_tmp(CompilerDirectives* dir) {33_tmp_depth++;34dir->set_next(_tmp_top);35_tmp_top = dir;36}3738CompilerDirectives* DirectivesParser::pop_tmp() {39if (_tmp_top == NULL) {40return NULL;41}42CompilerDirectives* tmp = _tmp_top;43_tmp_top = _tmp_top->next();44tmp->set_next(NULL);45_tmp_depth--;46return tmp;47}4849void DirectivesParser::clean_tmp() {50CompilerDirectives* tmp = pop_tmp();51while (tmp != NULL) {52delete tmp;53tmp = pop_tmp();54}55assert(_tmp_depth == 0, "Consistency");56}5758int DirectivesParser::parse_string(const char* text, outputStream* st) {59DirectivesParser cd(text, st, false);60if (cd.valid()) {61return cd.install_directives();62} else {63cd.clean_tmp();64st->flush();65st->print_cr("Parsing of compiler directives failed");66return -1;67}68}6970bool DirectivesParser::has_file() {71return CompilerDirectivesFile != NULL;72}7374bool DirectivesParser::parse_from_flag() {75return parse_from_file(CompilerDirectivesFile, tty);76}7778bool DirectivesParser::parse_from_file(const char* filename, outputStream* st) {79assert(filename != NULL, "Test before calling this");80if (!parse_from_file_inner(filename, st)) {81st->print_cr("Could not load file: %s", filename);82return false;83}84return true;85}8687bool DirectivesParser::parse_from_file_inner(const char* filename, outputStream* stream) {88struct stat st;89ResourceMark rm;90if (os::stat(filename, &st) == 0) {91// found file, open it92int file_handle = os::open(filename, 0, 0);93if (file_handle != -1) {94// read contents into resource array95char* buffer = NEW_RESOURCE_ARRAY(char, st.st_size+1);96ssize_t num_read = os::read(file_handle, (char*) buffer, st.st_size);97if (num_read >= 0) {98buffer[num_read] = '\0';99// close file100os::close(file_handle);101return parse_string(buffer, stream) > 0;102}103}104}105return false;106}107108int DirectivesParser::install_directives() {109// Check limit110if (!DirectivesStack::check_capacity(_tmp_depth, _st)) {111clean_tmp();112return 0;113}114115// Pop from internal temporary stack and push to compileBroker.116CompilerDirectives* tmp = pop_tmp();117int i = 0;118while (tmp != NULL) {119i++;120DirectivesStack::push(tmp);121tmp = pop_tmp();122}123if (i == 0) {124_st->print_cr("No directives in file");125return 0;126} else {127_st->print_cr("%i compiler directives added", i);128if (CompilerDirectivesPrint) {129// Print entire directives stack after new has been pushed.130DirectivesStack::print(_st);131}132return i;133}134}135136DirectivesParser::DirectivesParser(const char* text, outputStream* st, bool silent)137: JSON(text, silent, st), depth(0), current_directive(NULL), current_directiveset(NULL), _tmp_top(NULL), _tmp_depth(0) {138#ifndef PRODUCT139memset(stack, 0, MAX_DEPTH * sizeof(stack[0]));140#endif141parse();142}143144DirectivesParser::~DirectivesParser() {145assert(_tmp_top == NULL, "Consistency");146assert(_tmp_depth == 0, "Consistency");147}148149const DirectivesParser::key DirectivesParser::keys[] = {150// name, keytype, allow_array, allowed_mask, set_function151{ "c1", type_c1, 0, mask(type_directives), NULL, UnknownFlagType },152{ "c2", type_c2, 0, mask(type_directives), NULL, UnknownFlagType },153{ "match", type_match, 1, mask(type_directives), NULL, UnknownFlagType },154{ "inline", type_inline, 1, mask(type_directives) | mask(type_c1) | mask(type_c2), NULL, UnknownFlagType },155156// Global flags157#define common_flag_key(name, type, dvalue, compiler) \158{ #name, type_flag, 0, mask(type_directives) | mask(type_c1) | mask(type_c2), &DirectiveSet::set_##name, type##Flag},159compilerdirectives_common_flags(common_flag_key)160compilerdirectives_c2_flags(common_flag_key)161compilerdirectives_c1_flags(common_flag_key)162#undef common_flag_key163};164165const DirectivesParser::key DirectivesParser::dir_array_key = {166"top level directives array", type_dir_array, 0, 1 // Lowest bit means allow at top level167};168const DirectivesParser::key DirectivesParser::dir_key = {169"top level directive", type_directives, 0, mask(type_dir_array) | 1 // Lowest bit means allow at top level170};171const DirectivesParser::key DirectivesParser::value_array_key = {172"value array", type_value_array, 0, UINT_MAX // Allow all, checked by allow_array on other keys, not by allowed_mask from this key173};174175const DirectivesParser::key* DirectivesParser::lookup_key(const char* str, size_t len) {176for (size_t i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) {177if (strncasecmp(keys[i].name, str, len) == 0) {178return &keys[i];179}180}181return NULL;182}183184uint DirectivesParser::mask(keytype kt) {185return 1 << (kt + 1);186}187188bool DirectivesParser::push_key(const char* str, size_t len) {189bool result = true;190const key* k = lookup_key(str, len);191192if (k == NULL) {193// os::strdup194char* s = NEW_C_HEAP_ARRAY(char, len + 1, mtCompiler);195strncpy(s, str, len);196s[len] = '\0';197error(KEY_ERROR, "No such key: '%s'.", s);198FREE_C_HEAP_ARRAY(char, s);199return false;200}201202return push_key(k);203}204205bool DirectivesParser::push_key(const key* k) {206assert(k->allowedmask != 0, "not allowed anywhere?");207208// Exceeding the stack should not be possible with a valid compiler directive,209// and an invalid should abort before this happens210assert(depth < MAX_DEPTH, "exceeded stack depth");211if (depth >= MAX_DEPTH) {212error(INTERNAL_ERROR, "Stack depth exceeded.");213return false;214}215216assert(stack[depth] == NULL, "element not nulled, something is wrong");217218if (depth == 0 && !(k->allowedmask & 1)) {219error(KEY_ERROR, "Key '%s' not allowed at top level.", k->name);220return false;221}222223if (depth > 0) {224const key* prev = stack[depth - 1];225if (!(k->allowedmask & mask(prev->type))) {226error(KEY_ERROR, "Key '%s' not allowed after '%s' key.", k->name, prev->name);227return false;228}229}230231stack[depth] = k;232depth++;233return true;234}235236const DirectivesParser::key* DirectivesParser::current_key() {237assert(depth > 0, "getting key from empty stack");238if (depth == 0) {239return NULL;240}241return stack[depth - 1];242}243244const DirectivesParser::key* DirectivesParser::pop_key() {245assert(depth > 0, "popping empty stack");246if (depth == 0) {247error(INTERNAL_ERROR, "Popping empty stack.");248return NULL;249}250depth--;251252const key* k = stack[depth];253#ifndef PRODUCT254stack[depth] = NULL;255#endif256257return k;258}259260bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* option_key, DirectiveSet* set) {261262void (DirectiveSet::*test)(void *args);263test = option_key->set;264265switch (t) {266case JSON_TRUE:267if (option_key->flag_type != boolFlag) {268error(VALUE_ERROR, "Cannot use bool value for an %s flag", flag_type_names[option_key->flag_type]);269return false;270} else {271bool val = true;272(set->*test)((void *)&val);273}274break;275276case JSON_FALSE:277if (option_key->flag_type != boolFlag) {278error(VALUE_ERROR, "Cannot use bool value for an %s flag", flag_type_names[option_key->flag_type]);279return false;280} else {281bool val = false;282(set->*test)((void *)&val);283}284break;285286case JSON_NUMBER_INT:287if (option_key->flag_type == intxFlag) {288intx ival = v->int_value;289(set->*test)((void *)&ival);290} else if (option_key->flag_type == uintxFlag) {291uintx ival = v->uint_value;292(set->*test)((void *)&ival);293} else if (option_key->flag_type == doubleFlag) {294double dval = (double)v->int_value;295(set->*test)((void *)&dval);296} else {297error(VALUE_ERROR, "Cannot use int value for an %s flag", flag_type_names[option_key->flag_type]);298return false;299}300break;301302case JSON_NUMBER_FLOAT:303if (option_key->flag_type != doubleFlag) {304error(VALUE_ERROR, "Cannot use double value for an %s flag", flag_type_names[option_key->flag_type]);305return false;306} else {307double dval = v->double_value;308(set->*test)((void *)&dval);309}310break;311312case JSON_STRING:313if (option_key->flag_type != ccstrFlag && option_key->flag_type != ccstrlistFlag) {314error(VALUE_ERROR, "Cannot use string value for a %s flag", flag_type_names[option_key->flag_type]);315return false;316} else {317char* s = NEW_C_HEAP_ARRAY(char, v->str.length+1, mtCompiler);318strncpy(s, v->str.start, v->str.length + 1);319s[v->str.length] = '\0';320(set->*test)((void *)&s);321322if (strncmp(option_key->name, "ControlIntrinsic", 16) == 0) {323ControlIntrinsicValidator validator(s, false/*disabled_all*/);324325if (!validator.is_valid()) {326error(VALUE_ERROR, "Unrecognized intrinsic detected in ControlIntrinsic: %s", validator.what());327return false;328}329} else if (strncmp(option_key->name, "DisableIntrinsic", 16) == 0) {330ControlIntrinsicValidator validator(s, true/*disabled_all*/);331332if (!validator.is_valid()) {333error(VALUE_ERROR, "Unrecognized intrinsic detected in DisableIntrinsic: %s", validator.what());334return false;335}336}337}338break;339340default:341assert(0, "Should not reach here.");342}343return true;344}345346bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) {347348const key* option_key = pop_key();349const key* enclosing_key = current_key();350351if (option_key->type == value_array_key.type) {352// Multi value array, we are really setting the value353// for the key one step further up.354option_key = pop_key();355enclosing_key = current_key();356357// Repush option_key and multi value marker, since358// we need to keep them until all multi values are set.359push_key(option_key);360push_key(&value_array_key);361}362363switch (option_key->type) {364case type_flag:365{366if (current_directiveset == NULL) {367assert(depth == 2, "Must not have active directive set");368369if (!set_option_flag(t, v, option_key, current_directive->_c1_store)) {370return false;371}372if (!set_option_flag(t, v, option_key, current_directive->_c2_store)) {373return false;374}375} else {376assert(depth > 2, "Must have active current directive set");377if (!set_option_flag(t, v, option_key, current_directiveset)) {378return false;379}380}381break;382}383384case type_match:385if (t != JSON_STRING) {386error(VALUE_ERROR, "Key of type %s needs a value of type string", option_key->name);387return false;388}389if (enclosing_key->type != type_directives) {390error(SYNTAX_ERROR, "Match keyword can only exist inside a directive");391return false;392}393{394char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler);395strncpy(s, v->str.start, v->str.length);396s[v->str.length] = '\0';397398const char* error_msg = NULL;399if (!current_directive->add_match(s, error_msg)) {400assert (error_msg != NULL, "Must have valid error message");401error(VALUE_ERROR, "Method pattern error: %s", error_msg);402}403FREE_C_HEAP_ARRAY(char, s);404}405break;406407case type_inline:408if (t != JSON_STRING) {409error(VALUE_ERROR, "Key of type %s needs a value of type string", option_key->name);410return false;411}412{413//char* s = strndup(v->str.start, v->str.length);414char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler);415strncpy(s, v->str.start, v->str.length);416s[v->str.length] = '\0';417418const char* error_msg = NULL;419if (current_directiveset == NULL) {420if (current_directive->_c1_store->parse_and_add_inline(s, error_msg)) {421if (!current_directive->_c2_store->parse_and_add_inline(s, error_msg)) {422assert (error_msg != NULL, "Must have valid error message");423error(VALUE_ERROR, "Method pattern error: %s", error_msg);424}425} else {426assert (error_msg != NULL, "Must have valid error message");427error(VALUE_ERROR, "Method pattern error: %s", error_msg);428}429} else {430if (!current_directiveset->parse_and_add_inline(s, error_msg)) {431assert (error_msg != NULL, "Must have valid error message");432error(VALUE_ERROR, "Method pattern error: %s", error_msg);433}434}435FREE_C_HEAP_ARRAY(char, s);436}437break;438439case type_c1:440current_directiveset = current_directive->_c1_store;441if (t != JSON_TRUE && t != JSON_FALSE) {442error(VALUE_ERROR, "Key of type %s needs a true or false value", option_key->name);443return false;444}445break;446447case type_c2:448current_directiveset = current_directive->_c2_store;449if (t != JSON_TRUE && t != JSON_FALSE) {450error(VALUE_ERROR, "Key of type %s needs a true or false value", option_key->name);451return false;452}453break;454455default:456break;457}458459return true;460}461462bool DirectivesParser::callback(JSON_TYPE t, JSON_VAL* v, uint rlimit) {463const key* k;464465if (depth == 0) {466switch (t) {467case JSON_ARRAY_BEGIN:468return push_key(&dir_array_key);469470case JSON_OBJECT_BEGIN:471// push synthetic dir_array472push_key(&dir_array_key);473assert(depth == 1, "Make sure the stack are aligned with the directives");474break;475476default:477error(SYNTAX_ERROR, "DirectivesParser can only start with an array containing directive objects, or one single directive.");478return false;479}480}481if (depth == 1) {482switch (t) {483case JSON_OBJECT_BEGIN:484// Parsing a new directive.485current_directive = new CompilerDirectives();486return push_key(&dir_key);487488case JSON_ARRAY_END:489k = pop_key();490491if (k->type != type_dir_array) {492error(SYNTAX_ERROR, "Expected end of directives array");493return false;494}495return true;496497default:498error(SYNTAX_ERROR, "DirectivesParser can only start with an array containing directive objects, or one single directive.");499return false;500}501} else {502switch (t) {503case JSON_OBJECT_BEGIN:504k = current_key();505switch (k->type) {506case type_c1:507current_directiveset = current_directive->_c1_store;508return true;509case type_c2:510current_directiveset = current_directive->_c2_store;511return true;512513case type_dir_array:514return push_key(&dir_key);515516default:517error(SYNTAX_ERROR, "The key '%s' does not allow an object to follow.", k->name);518return false;519}520return false;521522case JSON_OBJECT_END:523k = pop_key();524switch (k->type) {525case type_c1:526case type_c2:527// This is how we now if options apply to a single or both directive sets528current_directiveset = NULL;529break;530531case type_directives:532// Check, finish and push to stack!533if (current_directive->match() == NULL) {534error(INTERNAL_ERROR, "Directive missing required match.");535return false;536}537current_directive->finalize(_st);538push_tmp(current_directive);539current_directive = NULL;540break;541542default:543error(INTERNAL_ERROR, "Object end with wrong key type on stack: %s.", k->name);544ShouldNotReachHere();545return false;546}547return true;548549case JSON_ARRAY_BEGIN:550k = current_key();551if (!(k->allow_array_value)) {552if (k->type == type_dir_array) {553error(SYNTAX_ERROR, "Array not allowed inside top level array, expected directive object.");554} else {555error(VALUE_ERROR, "The key '%s' does not allow an array of values.", k->name);556}557return false;558}559return push_key(&value_array_key);560561case JSON_ARRAY_END:562k = pop_key(); // Pop multi value marker563assert(k->type == value_array_key.type, "array end for level != 0 should terminate multi value");564k = pop_key(); // Pop key for option that was set565return true;566567case JSON_KEY:568return push_key(v->str.start, v->str.length);569570case JSON_STRING:571case JSON_NUMBER_INT:572case JSON_NUMBER_FLOAT:573case JSON_TRUE:574case JSON_FALSE:575case JSON_NULL:576return set_option(t, v);577578default:579error(INTERNAL_ERROR, "Unknown JSON type: %d.", t);580ShouldNotReachHere();581return false;582}583}584}585586587588