United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4649007 : Document classfile attributes for compilation date/time + debugging

Details
Type:
Enhancement
Submit Date:
2002-03-07
Status:
Closed
Updated Date:
2013-03-20
Project Name:
JDK
Resolved Date:
2013-03-20
Component:
specification
OS:
windows_nt,windows_2000
Sub-Component:
vm
CPU:
x86
Priority:
P4
Resolution:
Not an Issue
Affected Versions:
1.3.1,1.4.0
Fixed Versions:

Related Reports

Sub Tasks

Description

Name: gm110360			Date: 03/07/2002


FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION :
Windows 2000 Pro Sp1

ADDITIONAL OPERATING SYSTEMS :
Windows NT 4.0
Linux
etc.


A DESCRIPTION OF THE PROBLEM :
I would like to be able to get at execution time, the
compilation date/time of a class.  Right now, I can do this
by:

1. If the class file is in a JAR file, getting the JAR URL,
then the JAR File, then the JarEntry, and then the
date/time.

2. If the class file is NOT in a JAR file, getting the path
to the class file, and getting its lastModified date/time.

While I have this working just fine in my Java
applications, it would really be nice to be able to
retrieve the compilation date/time of the class as an
attribute of the class;  e.g.:

long dateTime = MyClass.class.getBuildTime();

This would be a LOT simpler and more portable as well.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. N/A
2.
3.

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
try {
    jarUrl  = Main.class.getResource( "Main.class" );
    jarFile = ((JarURLConnection) jarUrl.openConnection()).getJarFile();
    log( logLevel_DEBUG, "Jar file: " + jarFile.getName() );
} catch ( Exception exception ){	// No JAR file
    log( logLevel_DEBUG, exception );
}

try {
    return new Date(  pathName != null	? new File( pathName
					+ fileName ).lastModified()
		    : jarFile  != null	? jarFile.getEntry( fileName ).getTime()
					: new File( fileName ).lastModified() );
} catch ( Exception exception ){
    log( logLevel_DEBUG, exception );
    throw new FileNotFoundException( fileName );
}

---------- END SOURCE ----------

CUSTOMER WORKAROUND :
Code segment above
(Review ID: 143826) 
======================================================================

Name: jl125535			Date: 03/07/2002


FULL PRODUCT VERSION :
java version "1.3.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24)
Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)


FULL OPERATING SYSTEM VERSION :
Windows NT Version 4.0

ADDITIONAL OPERATING SYSTEMS :
(All others)


A DESCRIPTION OF THE PROBLEM :
Unrelated bugs: 4615070

It would be nice to add predefined identifiers to the Java
language which evaluate at compile time to strings that
specify the date and time of compilation.  These would be
similar in spirit to the predefined '__DATE__' and
'__TIME__' macros of C/C++, but could be provided without
all of the ugliness of a preprocessor.

Rather than invent new keywords for this, it would probably
be better to invent a new "compile-time information" class
that is specially handled by the javac compiler.

For example, I'd like to embed the date and time that my
class was compiled, in the form of a "what-string" that
is accessible by the unix what(1) utility:

    class Foo
    {
        // Embedded identification info
        static final String   REV =
            "@(#)$Header$\n";

        static final String   BUILT =
            "@(#)Built: " + CompileTime.DATE
            + " " + CompileTime.TIME + "\n";

        ...
    }

RCS users will recognize the first constant, 'REV', which
is expanded into source code revision information about
the source file, which winds up being embedded within the
bytecode (.class) file, and which can be displayed by a
user with the what(1) utility.

The second constant, 'BUILT', utilizes the proposed
'java.lang.CompileTime' class, which contains the members
'DATE' and 'TIME'.  These members are evaluated at compile
time to the date and time, respectively, that the Java
compiler was run on the source file.  The resulting string
constant winds up being embedded in the bytecode (.class)
file.

A recommended format for each of these constants is:

    DATE:  "yyyy-mm-dd"    (e.g., "2002-03-15")
    TIME:  "hh:mm:ss.mmm"  (e.g., "14:33:08.166")

These formats are based on the ISO 8601 formats for
specifying dates and time, and thus do not reflect any
particular region-specific format.  It would also be
convenient if these values were relative to UTC instead of
the local timezone, making their values independent of
the location that the source file was compiled.

Other uses include things like:

    System.out.println("Class " + this.getClass.getName()
        + " compiled on "
        + CompileTime.DATE.substring(5, 10) + " at "
        + CompileTime.TIME.substring(0, 5) + ".");

which would display something like:

    Class Foo compiled on 03-15 at 14:33.

Formally, the CompileTime class is:

    public final class java.lang.CompileTime
    {
        public static final String  DATE = "yyyy-mm-dd";
        public static final String  TIME = "hh:mm:ss.mmm";
    }

Other compile-time member constants could be added (e.g.,
user-ID, working directory, source filename, etc.), but we
don't want to overdesign this feature just yet.  Perhaps
one more member:

    public static final String  VERSION = "x.x.x";

which is the version number of the compiler/JDK.


This bug can be reproduced always.

CUSTOMER WORKAROUND :
I use a specially written program as part of my compilation
process that generates Java source code containing the
current date and time (and a few other informational items)
as constant members in a class, which I then have to
compile separately and include in my package jarfile.
(Review ID: 143771)
======================================================================

                                    

Comments
As a general rule, if a debugging attribute isn't important enough to be processed by pack200 --strip-debug, then it's second class and should not be in the JVMS.
                                     
2013-03-20
EVALUATION

Further to CompilationID/SourceID, javac also generates CharacterRangeTable when -Xjcov is used. CharacterRangeTable appeared in JDK 1.4, so the JVMS must say that it is only defined as a standard attribute for classfile versions >=48.0. Arguably, it should only be format-checked in >=51.0.

--
The CharacterRangeTable attribute is an optional variable-length attribute in the attributes table of a Code(??4.7.3) attribute. It may be used by debuggers to determine which part of the Java virtual machine code array corresponds to a given position in the source file or to determine what section of source code corresponds to a given index into the code array. The CharacterRangeTable attribute consists of an array of character range entries. Each character range entry within the table associates a range of indices in the code array with a range of character indices in the source file. If the source file is viewed as an array of characters, a character index is the corresponding index into this array. Note that character indices are not the same as byte indices as multi-byte characters may be present in the source file. Each character range entry includes a flag which indicates what kind of range is described: statement, assignment, method call, etc. Both code index ranges and character ranges may nest within other ranges, but they may not partially overlap. Thus, a given code index may correspond to several character range entries and in turn several character ranges, but there will be a smallest character range, and for each kind of range in which it is enclosed there will be a smallest character range. Similarly, a given character index may correspond to several character range entries and in turn several code index ranges, but there will be a smallest code index range, and for each kind of range in which it is enclosed there will be a smallest code index range. The character range entries may appear in any order.

The CharacterRangeTable attribute has the following format:

    CharacterRangeTable_attribute {
    	u2 attribute_name_index;
    	u4 attribute_length;
    	u2 character_range_table_length;
    	{  u2 start_pc;
    	   u2 end_pc;
    	   u4 character_range_start;
    	   u4 character_range_end;
    	   u2 flags;
    	} character_range_table[character_range_table_length];
    }


The items of the CharacterRangeTable_attribute structure are as follows:

attribute_name_index
    The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info (??4.4.7) structure representing the string "CharacterRangeTable".

attribute_length
    The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes.

character_range_table_length
    The value of the character_range_table_length item indicates the number of entries in the character_range_table array.

character_range_table[]
    Each character_range_table entry must contain the following five items:

start_pc
    The value of the start_pc item must indicate the index into the code array at which the code for this character range begins. The value of start_pc must be less than the value of the code_length item of the Code attribute of which this CharacterRangeTable is an attribute.

end_pc
    The value of the end_pc item must indicate the index into the code array at which the code for this character range ends. The value of end_pc must be greater than or equal to start_pc and must be less than the value of the code_length item of the Code attribute of which this CharacterRangeTable is an attribute.

character_range_start
    The value of the character_range_start item must contain the encoded index into the source file where the character range begins. The value is constructed from the line_number/column_number pair in the following way: line_number << 10 + column_number. Where the source file is viewed as an array of (possibly multi-byte) characters.

character_range_end
    The value of the character_range_startitem must contain the encoded index into the source file where the characterrange ends. The value is constructed from the line_number/column_number pair in the following way: line_number << 10 + column_number.

flags
    The value of the flags item describes the kind of range. Multiple flags may be set within flags.Flags are defined in terms of "the grammar" which means The Grammar of the Java Programming Language in TheJavaTM Language Specification
    Flag Name 	Value 	Meaning
    CRT_STATEMENT 	0x0001 	Range is a Statement (except ExpressionStatement), StatementExpression (14.8), as well as each
    VariableDeclaratorId = VariableInitializer of LocalVariableDeclarationStatement (14.4) or FieldDeclaration (8.3) in the grammar.
    CRT_BLOCK 	0x0002 	Range is a Block in the grammar.
    CRT_ASSIGNMENT 	0x0004 	Range is an assignment expression - Expression1 AssignmentOperator Expression1 in the grammar as well as increment and decrement expressions (both prefix and postfix).
    CRT_FLOW_CONTROLLER 	0x0008 	An expression whose value will effect control flow. Flowcon in the following:

    if ( Flowcon ) Statement [else Statement]
    for ( ForInitOpt ; [Flowcon] ; ForUpdateOpt ) Statement
    while ( Flowcon ) Statement
    do Statement while ( Flowcon ) ;
    switch ( Flowcon ) { SwitchBlockStatementGroups }
    Flowcon || Expression3
    Flowcon && Expression3
    Flowcon ? Expression : Expression1

    CRT_FLOW_TARGET 	0x0010 	Statement or expression effected by a CRT_FLOW_CONTROLLER. Flowtarg in the following:

    if ( Flowcon ) Flowtarg [else Flowtarg]
    for ( ForInitOpt ; [Flowcon] ; ForUpdateOpt ) Flowtarg
    while ( Flowcon ) Flowtarg
    do Flowtarg while ( Flowcon ) ;
    Flowcon || Flowtarg
    Flowcon && Flowtarg
    Flowcon ? Flowtarg : Flowtarg

    as well as each SwitchBlockStatementGroup.
    CRT_INVOKE 	0x0020 	Method invocation. For example: Identifier Arguments.
    CRT_CREATE 	0x0040 	New object creation. For example: new Creator.
    CRT_BRANCH_TRUE 	0x0080 	A condition encoded in the branch instruction immediately contained in the code range for this item is not inverted towards the corresponding branch condition in the source code. I.e. actual jump occurs if and only if the the source code branch condition evaluates to true. Entries of this type are produced only for conditions that are listed in the description of CRT_FLOW_CONTROLLER flag. The source range for the entry contains flow controlling expression. start_pc field for an entry of this type must point to a branch instruction: if_acmp<cond>, if_icmp<cond>, if<cond>, ifnonull, ifnull or goto. CRT_BRANCH_TRUE and CRT_BRANCH_FALSE are special kinds of entries that can be used to determine what branch of a condition was chosen during the runtime.
    CRT_BRANCH_FALSE 	0x0100 	A condition encoded in the branch instruction immediately contained in the code range for this item is inverted towards the corresponding branch condition in the source code. I.e. actual jump occurs if and only if the the source code branch condition evaluates to false. Entries of this type are produced only for conditions that are listed in the description of CRT_FLOW_CONTROLLER flag. The source range for the entry contains flow controlling expression. start_pc field for an entry of this type must point to a branch instruction: if_acmp<cond>, if_icmp<cond>, if<cond>, ifnonull, ifnull or goto.


    All bits of the flags item not assigned above are reserved for future use. They should be set to zero in generated class files and should be ignored by Java virtual machine implementations.
                                     
2008-05-12
EVALUATION

Running javac with -Xjcov emits the SourceID and CompilationID attributes:

- SourceID is the last modified time of the source file (as reported by the filesystem, in milliseconds) when the classfile is emitted.

- CompilationID is the value of System.currentTimeMillis() when the classfile is emitted.

- In a given classfile, CompilationID is always equal to or later than SourceID.

- Different classfiles emitted by the same javac invocation can have different CompilationIDs.

- The structure of both attributes is:
  u2 (attribute_name_index)
  u4 (attribute_length, ==8)
  u2 (source_id_index/compilation_id_index) // Points to a UTF8 string in the constant pool
                                     
2008-05-12
EVALUATION

This would be a new mandate for all compilers/IDEs. I'm not at all sure it's
worth the weight. We should consider it for the next rev. of the class file
format.

###@###.### 2002-03-07
                                     
2002-03-07



Hardware and Software, Engineered to Work Together