JDK-6771309 : debugging AD files is difficult without #line directives in generated code
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2008-11-13
  • Updated: 2011-04-19
  • Resolved: 2011-04-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 Other
6u14Fixed 7 b42Fixed hs14Fixed
Description
When debugging the back end of the server compiler, we occasionally need to single-step into code that has been written in the AD file.  This takes into generated files like ad_sparc.cpp, but we really want to examine and edit the original code in sparc.ad.

What's needed is more and better #line directives in the generated code, and for ADLC itself to accept #line directives.

Comments
EVALUATION hs14 integration
28-04-2009

EVALUATION http://hg.openjdk.java.net/jdk7/hotspot-comp/hotspot/rev/284d0af00d53
09-12-2008

SUGGESTED FIX diff --git a/make/solaris/makefiles/adlc.make b/make/solaris/makefiles/adlc.make --- a/make/solaris/makefiles/adlc.make +++ b/make/solaris/makefiles/adlc.make @@ -54,9 +54,11 @@ Src_Dirs_I = ${Src_Dirs} $(GENERATED) Src_Dirs_I = ${Src_Dirs} $(GENERATED) INCLUDES += $(Src_Dirs_I:%=-I%) +# set flags for adlc compilation +CPPFLAGS = $(SYSDEFS) $(INCLUDES) + # Force assertions on. -SYSDEFS += -DASSERT -CPPFLAGS = $(SYSDEFS) $(INCLUDES) +CPPFLAGS += -DASSERT ifndef USE_GCC # We need libCstd.so for adlc @@ -141,7 +143,15 @@ all: $(GENERATEDFILES) # Note that product files are updated via "mv", which is atomic. TEMPDIR := $(OUTDIR)/mktmp$(shell echo $$$$) -ADLCFLAGS = -q -T +# Pass -D flags into ADLC. +ADLCFLAGS += $(SYSDEFS) + +# Note "+="; it is a hook so flags.make can add more flags, like -g or -DFOO. +ADLCFLAGS += -q -T + +# Normally, debugging is done directly on the ad_<arch>*.cpp files. +# But -g will put #line directives in those files pointing back to <arch>.ad. +#ADLCFLAGS += -g ifdef LP64 ADLCFLAGS += -D_LP64 @@ -190,7 +200,15 @@ refresh_adfiles: $(EXEC) $(SOURCE.AD) # ######################################################################### $(SOURCE.AD): $(SOURCES.AD) - $(QUIETLY) cat $(SOURCES.AD) > $(SOURCE.AD) + $(QUIETLY) $(PROCESS_AD_FILES) $(SOURCES.AD) > $(SOURCE.AD) + +#PROCESS_AD_FILES = cat +# Pass through #line directives, in case user enables -g option above: +PROCESS_AD_FILES = awk '{ \ + if (NR==1) need_lineno=1; \ + if (need_lineno && $$0 !~ /\/\//) \ + { print "\n\n\#line " NR " \"" FILENAME "\""; need_lineno=0 }; \ + print }' $(OUTDIR)/%.o: %.cpp @echo Compiling $< diff --git a/src/share/vm/adlc/adlparse.cpp b/src/share/vm/adlc/adlparse.cpp --- a/src/share/vm/adlc/adlparse.cpp +++ b/src/share/vm/adlc/adlparse.cpp @@ -108,6 +108,7 @@ void ADLParser::parse() { else if (!strcmp(ident, "pipeline")) pipe_parse(); else if (!strcmp(ident, "definitions")) definitions_parse(); else if (!strcmp(ident, "peephole")) peep_parse(); + else if (!strcmp(ident, "#line")) preproc_line(); else if (!strcmp(ident, "#define")) preproc_define(); else if (!strcmp(ident, "#undef")) preproc_undef(); else { @@ -903,11 +904,7 @@ void ADLParser::enc_class_parse_block(En skipws_no_preproc(); // Skip leading whitespace // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block if (_AD._adlocation_debug) { - const char* file = _AD._ADL_file._name; - int line = linenum(); - char* location = (char *)malloc(strlen(file) + 100); - sprintf(location, "#line %d \"%s\"\n", line, file); - encoding->add_code(location); + encoding->add_code(get_line_string()); } // Collect the parts of the encode description @@ -2746,7 +2743,8 @@ Predicate *ADLParser::pred_parse(void) { char *rule = NULL; // String representation of predicate skipws(); // Skip leading whitespace - if ( (rule = get_paren_expr("pred expression")) == NULL ) { + int line = _linenum; + if ( (rule = get_paren_expr("pred expression", true)) == NULL ) { parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n"); return NULL; } @@ -3942,8 +3940,7 @@ char* ADLParser::find_cpp_block(const ch next_char(); // Skip block delimiter skipws_no_preproc(); // Skip leading whitespace cppBlock = _ptr; // Point to start of expression - const char* file = _AD._ADL_file._name; - int line = linenum(); + int line = _linenum; next = _ptr + 1; while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) { next_char_or_line(); @@ -3958,15 +3955,14 @@ char* ADLParser::find_cpp_block(const ch _curchar = *_ptr; // Maintain invariant // Prepend location descriptor, for debugging. - char* location = (char *)malloc(strlen(file) + 100); - *location = '\0'; - if (_AD._adlocation_debug) - sprintf(location, "#line %d \"%s\"\n", line, file); - char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + 1); - strcpy(result, location); - strcat(result, cppBlock); - cppBlock = result; - free(location); + if (_AD._adlocation_debug) { + char* location = get_line_string(line); + char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + 1); + strcpy(result, location); + strcat(result, cppBlock); + cppBlock = result; + free(location); + } } return cppBlock; @@ -4036,13 +4032,23 @@ char* ADLParser::get_expr(const char *de // Helper function around get_expr // Sets _curchar to '(' so that get_paren_expr will search for a matching ')' -char *ADLParser::get_paren_expr(const char *description) { +char *ADLParser::get_paren_expr(const char *description, bool include_location) { + int line = _linenum; if (_curchar != '(') // Escape if not valid starting position return NULL; next_char(); // Skip the required initial paren. char *token2 = get_expr(description, ")"); if (_curchar == ')') next_char(); // Skip required final paren. + if (include_location && _AD._adlocation_debug) { + // Prepend location descriptor, for debugging. + char* location = get_line_string(line); + char* result = (char *)malloc(strlen(location) + strlen(token2) + 1); + strcpy(result, location); + strcat(result, token2); + token2 = result; + free(location); + } return token2; } @@ -4430,6 +4436,35 @@ void ADLParser::get_effectlist(FormDict } } + +//-------------------------------preproc_line---------------------------------- +// A "#line" keyword has been seen, so parse the rest of the line. +void ADLParser::preproc_line(void) { + int line = get_int(); + skipws_no_preproc(); + const char* file = NULL; + if (_curchar == '"') { + next_char(); // Move past the initial '"' + file = _ptr; + while (true) { + if (_curchar == '\n') { + parse_err(SYNERR, "missing '\"' at end of #line directive"); + return; + } + if (_curchar == '"') { + *_ptr = '\0'; // Terminate the string + next_char(); + skipws_no_preproc(); + break; + } + next_char(); + } + } + ensure_end_of_line(); + if (file != NULL) + _AD._ADL_file._name = file; + _linenum = line; +} //------------------------------preproc_define--------------------------------- // A "#define" keyword has been seen, so parse the rest of the line. @@ -4494,6 +4529,7 @@ void ADLParser::parse_err(int flag, cons // A preprocessor directive has been encountered. Be sure it has fallen at // the begining of a line, or else report an error. void ADLParser::ensure_start_of_line(void) { + if (_curchar == '\n') { next_line(); return; } assert( _ptr >= _curline && _ptr < _curline+strlen(_curline), "Must be able to find which line we are in" ); @@ -4662,6 +4698,7 @@ char ADLParser::cur_char() { //---------------------------next_char----------------------------------------- void ADLParser::next_char() { + if (_curchar == '\n') parse_err(WARN, "must call next_line!"); _curchar = *++_ptr; // if ( _curchar == '\n' ) { // next_line(); @@ -4682,6 +4719,18 @@ void ADLParser::next_char_or_line() { //---------------------------next_line----------------------------------------- void ADLParser::next_line() { _curline = _buf.get_line(); + _curchar = ' '; +} + +//------------------------get_line_string-------------------------------------- +// Prepended location descriptor, for debugging. +// Must return a malloced string (that can be freed if desired). +char* ADLParser::get_line_string(int linenum) { + const char* file = _AD._ADL_file._name; + int line = linenum ? linenum : _linenum; + char* location = (char *)malloc(strlen(file) + 100); + sprintf(location, "\n#line %d \"%s\"\n", line, file); + return location; } //-------------------------is_literal_constant--------------------------------- diff --git a/src/share/vm/adlc/adlparse.hpp b/src/share/vm/adlc/adlparse.hpp --- a/src/share/vm/adlc/adlparse.hpp +++ b/src/share/vm/adlc/adlparse.hpp @@ -93,6 +93,7 @@ protected: void pipe_parse(void); // Parse pipeline section void definitions_parse(void); // Parse definitions section void peep_parse(void); // Parse peephole rule definitions + void preproc_line(void); // Parse a #line statement void preproc_define(void); // Parse a #define statement void preproc_undef(void); // Parse an #undef statement @@ -226,7 +227,7 @@ protected: void get_effectlist(FormDict &effects, FormDict &operands); // Parse effect-operand pairs // Return the contents of a parenthesized expression. // Requires initial '(' and consumes final ')', which is replaced by '\0'. - char *get_paren_expr(const char *description); + char *get_paren_expr(const char *description, bool include_location = false); // Return expression up to next stop-char, which terminator replaces. // Does not require initial '('. Does not consume final stop-char. // Final stop-char is left in _curchar, but is also is replaced by '\0'. @@ -234,6 +235,8 @@ protected: char *find_cpp_block(const char *description); // Parse a C++ code block // Issue parser error message & go to EOL void parse_err(int flag, const char *fmt, ...); + // Create a location marker for this file and line. + char *get_line_string(int linenum = 0); // Return pointer to current character inline char cur_char(void); diff --git a/src/share/vm/adlc/dfa.cpp b/src/share/vm/adlc/dfa.cpp --- a/src/share/vm/adlc/dfa.cpp +++ b/src/share/vm/adlc/dfa.cpp @@ -458,7 +458,7 @@ void ArchDesc::buildDFA(FILE* fp) { class dfa_shared_preds { - enum { count = 2 }; + enum { count = 4 }; static bool _found[count]; static const char* _type [count]; @@ -479,11 +479,14 @@ class dfa_shared_preds { char c = *prev; switch( c ) { case ' ': + case '\n': return dfa_shared_preds::valid_loc(pred, prev); case '!': case '(': case '<': case '=': + return true; + case '"': // such as: #line 10 "myfile.ad"\n mypredicate return true; case '|': if( prev != pred && *(prev-1) == '|' ) return true; @@ -564,10 +567,14 @@ public: } }; // shared predicates, _var and _pred entry should be the same length -bool dfa_shared_preds::_found[dfa_shared_preds::count] = { false, false }; -const char* dfa_shared_preds::_type[dfa_shared_preds::count] = { "int", "bool" }; -const char* dfa_shared_preds::_var [dfa_shared_preds::count] = { "_n_get_int__", "Compile__current____select_24_bit_instr__" }; -const char* dfa_shared_preds::_pred[dfa_shared_preds::count] = { "n->get_int()", "Compile::current()->select_24_bit_instr()" }; +bool dfa_shared_preds::_found[dfa_shared_preds::count] + = { false, false, false, false }; +const char* dfa_shared_preds::_type[dfa_shared_preds::count] + = { "int", "jlong", "intptr_t", "bool" }; +const char* dfa_shared_preds::_var [dfa_shared_preds::count] + = { "_n_get_int__", "_n_get_long__", "_n_get_intptr_t__", "Compile__current____select_24_bit_instr__" }; +const char* dfa_shared_preds::_pred[dfa_shared_preds::count] + = { "n->get_int()", "n->get_long()", "n->get_intptr_t()", "Compile::current()->select_24_bit_instr()" }; void ArchDesc::gen_dfa_state_body(FILE* fp, Dict &minimize, ProductionState &status, Dict &operands_chained_from, int i) {
13-11-2008