PROPOSAL: Compiletime information access

rssh at gradsoft.com.ua rssh at gradsoft.com.ua
Tue Mar 24 08:02:07 PDT 2009


> Wouldn't this effectively kill off jikes, or any other compiler that
> wasn't
> itself implemented in Java?
>

 I think any compiler can load or spawn external JVM, if needed.


> Regardless of that, there's some potentially big problems with this that I
> don't see addressed in the proposal. Consider the code snippet below:
>
> import java.text.MessageFormat;
> import java.util.Date;
>
> class Bad {
>     private static final String HELLO = "Hello #{0} at {1,time} on
> {1,date}!";
>
>     public void myMethod(int i) {
>         System.out.println(MessageFormat.format(HELLO, i, new Date()));
>     }
>
>     public static void main(String[] args) {
>         for (int i = 0; i < 10; ++i)
>             Compiletime.eval(getClass(), "myMethod", i);
>     }
> }
>
> Although it looks like valid Java, it contains a lot of bugs:
>
>    - The arguments to Compiletime.eval (getClass() and i) aren't available
>    until runtime.

Yes, it was Compile-Time error.

>    - "myMethod" can't be called because we haven't compiled it's class
> yet.

 Or, thenks, I forgott sentence: 'Class, avaible in user classpath durong
compilation time'.

(I. e. I mean call classes from classpath, not sourcepath)

>    - MessageFormat.format relies on the current locale, which may be
>    different at compile time to run time.

 Yes. And the same with AnnotationProcessing (which can be called in
compile-time now).


>    - Compiletime.eval will only be called once, although it looks like it
>    should be called 10 times; then at runtime the program will iterate 10
> times
>    over an empty loop and exit.
>

 No.
    Compile-time error on supplying 'i' will be thrown, because parameters
of Compiletime.eval()  must be literal or result of compile-time call.

I.e. Compiletime.eval() is also constant expression.

>
> The main problem is the execution of arbitrary Java code at compile time.
> The code can contain dependencies on things which haven't been compiled
> yet,
> or libraries which are dynamically loaded at runtime; worse, it may depend

 Yes, I forgott to write sentence, that classes must be avaible at user
classpath before start of compilation.

> on an environment which may be different between compile time and runtime
> (quite likely when developing J2EE apps, for example). It also raises the
> questions around verification (how do you verify classes that you are

 They will be disappeared at all.

> evaluating during compilation?) and security (what security model does it
> operate under?).
>

 Security model of java compiler. We already have al this potential problems
with annotations processing, where any java code can be auto-discovered and
run. And practice shows that this is not the biggest problem of language.



> The other problem with the proposal is the Compiletime.exec() method.
> Allowing arbitrary commands to be executed introduces serious security
> implications to the compilation step. Currently, at least, you can compile


 Are you know, that you can execute arbitrary command during compilation
 in current javac compiler by call System.exec from auto discovered
annotation processor ?

So, nothing new here.


> code without having to worry about those.
>

Possibility to write unmaintainable code exists.

But if think in such way, than creation of turing-complete programming
language was fatal security error ;)



> Finally, because it looks like ordinary Java code it's easy to confuse the
> two, leading to mistakes like the loop body in the example.
>
> In my opinion, this is more suited to a separate preprocessor. A quick
> google found a few of those already available.
>
> Vil.
>
>
> 2009/3/24 <rssh at gradsoft.com.ua>
>
>>
>> AUTHOR:  Ruslan Shevchenko
>>
>> OVERVIEW:
>>
>>  FEATURE SUMMARY:
>>
>>   Add API to access compile-time context of current compiled element
>> from
>>  programs and annotation processors.
>>
>>  MAJOR ADVANTAGE:
>>
>>   Now compile time properties are unaccessible for programmer. This
>> meaning
>>  that some functionality (such as access to location of file and line)
>> is
>>  accessible only from debug version of program with technique, which is
>> not
>>  officially supported, some (such as access to time of compilation or
>>  to binding context of current program location) is not avaible at all.
>>
>>  MAJOR DISADVANTAGE
>>
>>   Inaccurate usage of this feature can cause producing of unmaintable
>> code.
>>
>>  ALTERNATIVES:
>>
>>   External preprocessing of java sources.
>>
>> EXAMPLES
>>
>> SIMPLE EXAMPLE:
>>
>> Example 1
>>
>>  if (traceCondigion) {
>>    log.trace(Compiletime.getFileName()+":"+
>>              Compiletime.getLineNumber());
>>  }
>>
>> Example 2
>>
>>  if (system.currentTimeMillis() - Compiletime.getTimeMillis() > 86400) {
>>     System.out.println("This file was compiled more than day ago");
>>  }
>>
>> Example 3
>>
>>  System.out.println("Superprogram by AAA AC, version:"+
>>                                      Compiletime.exec("svnversion"));
>>
>> ADVANCED EXAMPLE:
>>
>> Example 1
>>  // assuming that multiline strings are implemented:
>>
>>  int a=0;
>>  int b=1;
>>  Binding bindings = Compiletime.getInstance().getCurrentBindings();
>>  ScriptEngine velocity = ScriptEngineManager.get("velocity");
>>  try {
>>    String fname = Compiletime.getFileName();
>>    int    line  = Compiletime.getLineNumber();
>>    String s = velocity.eval("""
>>    #if ($a==$b)
>>        Something interesting here may be,
>>       Are you know that value of b is $b ?
>>    #else
>>       no mistics here.
>>    #end
>>    """,
>>    bindings);
>>  } catch (ScriptException ex){
>>     Sytem.err.println("error in inline velocity in "+fname+", "
>>                       "line "+line+1+ex.getLineNumber());
>>  }
>>
>>
>> Example 2
>>
>>  boolean isDemo = (Compiletime.eval(Properties.class,
>>                                   "getProperty","is.demo")!=null);
>>
>>  if (!isDemo) {
>>    String key = (String)Compiletime.eval(GenerateUniqueKey.class,
>>                                        "generate");
>>    LoadNotDemoClass();
>>  }
>>
>>
>> DETAILS:
>>
>>
>>
>>  Add to Java Library pseudo-objects java.lang.Compiletime with access to
>> compile-time properties and next signature:
>>
>> public class Compiletime
>> {
>>   /**
>>    * get filename of compiled call.
>>    * in case of generated source and avaible JSR-45 SMAP file
>>    * return file name of translated-source.
>>    **/
>>   public static String getFileName();
>>
>>   /**
>>    * get line number of compiled call.
>>    * in case of generated source and avaible JSR-45 SMAP file
>>    * return line number in translated-source.
>>    **/
>>   public static int getLineNumber();
>>
>>   /**
>>    * get class name where this call is placed.
>>    * in case of generated source and avaible JSR-45 SMAP file
>>    * return class name in translated-source.
>>    **/
>>   public static int getClassName();
>>
>>   /**
>>    * get method name where this call is placed.
>>    * in case of generated source and avaible JSR-45 SMAP file
>>    * return method name in translated-source.
>>    **/
>>   public static int getMethodName();
>>
>>
>>   /**
>>    * generate JSR223 bindings for given names in current compilation
>>    *context.
>>    *Names array must be empty or consists from string literals.
>>    **/
>>   public static Bindings getBindings(String ... names)
>>
>>
>>   /**
>>    * get time of compilation in miliseconds.
>>    **/
>>   public static long getTimeMillis();
>>
>>   /**
>>    * Execute os command in compile-time.
>>    *@command - must be a string literal or result of call of Compiletime
>>    * method, otherwise compile-time error is thrown
>>    **/
>>   public static String exec(String command)
>>   /**
>>    *  call java class at compile-time.
>>    *During processing this directive, compiler will
>>    *1. determinate, if class available in user path.
>>    *2. determinate, if exists method with appropriative number and types
>>    *  of parameters.
>>    *3. If such method is static - call one, otherwise
>>    *  3.1 if class have default constructor - create instance of object
>>    *      (otherwise throw compile-time error)
>>    *  3.2. Call methid with new-created instance.
>>    *  3.3. If method return some result - substitute output to result,
>>    *       on exception throw compile-time error.
>>    *@param classLiteral - must be a class literal for object to call.
>>    *@param methodName - must be a string literal with name of method to
>> call.
>>    *@param parameters - parameters of method to call. Must be a
>> literals,
>> or
>>    *    calls of Compiletime methods.
>>    **/
>>   public static Object eval(Class<?> classLiteral, String methodName,
>> Object .. params);
>>
>> }
>>
>>
>>
>> COMPILATION:
>>
>>  During compilation calls to compile time are changed to generation of
>> appriative constant expressions.
>>
>> String x = Compiletime.getFileName();
>> changed to
>> String x = "com/mycompany/package/MyClass.java";
>>
>> int x = Compiletime.getLinNumber();
>>  changed to
>> int x = 33;
>>
>> String x = getClassName()
>>  changed to
>> String x = "com.mycompany.package.MyClass";
>>
>>
>> class X
>> {
>>  int p1;
>>  String p2;
>>
>>  ...
>>  public void doSomething(int x, int y)
>>  {
>>    int local = x+y;
>>    Bindings bindings = Compiletime.getBindings();
>>    evalSomeScript(bindings);
>>  }
>>
>> }
>>
>>
>>  will translated to
>>
>> class X
>> {
>>  int p1;
>>  String p2;
>>  ...
>>
>>  public void doSomething(int x, int y)
>>  {
>>    int local = x+y;
>>    SimpleBinding binding=(SimpleBinging uniqueName= new SimpleBinding();
>>                           uniqueName.put("this",this);
>>                           uniqueName.put("p1",p1);
>>                           uniqueName.put("p2",p2);
>>                           uniqueName.put("x",x);
>>                           uniqueName.put("y",y);
>>                           uniqueName.put("local",local);
>>                           uniqueName );
>>    evalSomeScript(bindings);
>>  }
>>
>>
>> }
>>
>>  (assuming that Block Expressions for Java will be avaible. If not - it
>> will be necessory create own implementation of Bindings as part of
>> library).
>>
>> exec will be changed to Sting literal, with result of execution, i. e.
>> on Unix
>> String compiledBy = Compiletime.eval("whoami");
>> whill be translated to 'rssh'
>>
>> At last eval call is translated to
>>  - appropriative literal, if result of eval is primitive type or boxed
>>   primitivew type.
>>  - Call of code to unserialize constant byte array, which as serialized
>>   during compilation
>>  or throw compile-time error is object is not primitive type and not
>> implements Serializable.
>>
>> JLS changes: current scope of JLS is not touched.
>>
>> Btw, may be add to JLS chapter with name 'Compilation process' where
>> describe:
>>  - high level description of transforming source code to JVM classes.
>>  - process of automatic loading of annotation processors and when ones
>> are
>> used.
>>  - this API.
>>
>>
>> TESTING:
>>
>>  Special cases are:
>>  *  compability with JSR45
>>  *  testing of exec function is
>>
>> LIBRARY SUPPORT:
>>  None, or adding two classes (for Bindings implementation with filling
>> in
>> constructor and Unserializing Object utility) in depends of avaibility
>> of block expressions for Java
>>
>>  (May be exists sence add methods for retrieveing source location (i.e.
>> file
>>  name and line number retrieving) to javax.lang.model.element.Element to
>>  support better diagnostics.
>>
>> REFLECTIVE APIS: None
>>
>> OTHER CHANGES: None
>>
>> MIGRATION: None
>>
>> COMPABILITY
>>  None
>>
>> REFERENCES
>>
>>  http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4411102
>>  http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6439965
>>  http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4649007
>>
>> IMPLEMENTATION URL (optional)
>>
>>  None yet.
>>
>>
>>
>>
>>
>>
>>
>





More information about the coin-dev mailing list