17 May

Java+Spring : @Value annotations on final variables

So, using Java since, like, 24 hours.

Using Java is one of those things making you appreciate C#. Or well, just about any other language.

 

The cool part of using Java is that after the first waves of vomit have passed, you have to deal with using Spring, which causes a lot more waves – how can Java programmers feel fine in leaving so much control to such a monolith I don’t know.

 

Vomit aside, I found a little compiler+env issue – I’m probably about to state the obvious, but remember I’m using the language since just like 24hrs so…

 

Example 1

Let’s start with a standard class, using a variable initialized from configuration:

@Service
public class MyService {

 @Value("${foo.bar.url}")
 final String fooBarUrl = "";

 public void whatever() {
    URL url = new URL(fooBarUrl); // exception thrown here
 }

The above throws an exception, saying that the fooBarUrl doesn’t contain a valid protocol part (actually, it’s empty) just as if the variable wasn’t initialized. But – wow – peak it with the debugger.. and the value is there.  This is guaranteed to cause headaches.

 

Example 2

Let’s start with a standard class, using a variable initialized from configuration:

@Service
public class MyService {

 @Value("${foo.bar.url}")
 final String fooBarUrl;

 public MyService() {
    fooBarUrl = "";
 }
 
 public void whatever() {
   URL url = new URL(fooBarUrl); // it works!
 }

This works, but I wouldn’t trust it to run after JRE updates, read below to know why.

 

Example 3

Let’s start with a standard class, using a variable initialized from configuration:

@Service
public class MyService {

 @Value("${foo.bar.url}")
 String fooBarUrl;

  public void whatever() {
   URL url = new URL(fooBarUrl); // it works!
 }

This works, and is the good solution, even if code could overwrite fooBarUrl – something I would like to avoid.

 

Why

I can only guess why Example 1 doesn’t work and the reason why I don’t trust Example 2 even if it works.. Guess mode ON.

My guess is that the compiler sees the fooBarUrl initialized with a constant value outside of constructor code. The variable – in code – could not be overwritten in any way, so to optimize it replaces the variable accesses with a literal string – after all we declared it not to change. Because it has to support reflection in a meaningful way (i.e. not crashing) it still creates the backing store for the variable and that’s what gets accessed with reflection and.. by the debugger of course. So in essence the debugger correctly reports the variable value, but the code has been “changed” to use new URL(“”) instead of new URL(fooBarUrl);

Under this theory, Example2 works because the initialization is in the constructor and the compiler is not sophisticated enough to see that that is the only possible initialization path – thus it skips the “optimization” and goes on. Any “improvement” in the compiler could break this though.

Example3 is just clean.

While very debatable, I personally think this as a bug in the tool chain because, well, that optimization is quite hazardous. We live in a world where almost every program uses reflection heavily so compilers shouldn’t rely on finals/readonlys not to be overwritten, privates not to be changed from outside, etc. Either have the compiler/JIT be consistent, or disallow writing from reflection.

 

Filed under: Uncategorized

18 Mar

Detect Mono running in AOT mode

So, for MoonSharp (which is evolving a lot more than it was suggested by posts on this blog – heck I should write MORE), I needed to know if my library was running in FullAOT or not.

For those not knowing, AOT means “ahead of time”. Under a FullAOT execution, JITting is disabled and code is compiled “ahead of time”; this means all those scenarios which involve creating code on the fly at runtime will not work. This can be used for some optimizing scenario or for embedded systems and such, but the real use case is iOS, as apps on iOS cannot (due to licensing) create code at runtime – weird Apple rules.

Now, while an app usually knows whether it’s running on AOT or not, a class library might not now beforehand and yet that information might be useful.

For example MoonSharp userdata do a lot of reflection and back-and-forth calls between script and native code. As an optimization, it uses LambdaExpression.Compile calls to create wrappers at runtime and have performances which are orders of magnitude faster than reflection. However those calls break with an ExecutionEngineException on Mono FullAOT.

Now, here we have a little weird Mono thing which comes to help us.. don’t know if it’s a bug or intentional.

As per MSDN documentation, managed code cannot catch an ExecutionEngineException. Turns out that Mono behaves differently – at the very least regarding those EEEs which are thrown due to a JIT request in FullAOT.

Then the detection code gets simple enough:

private static void AttemptJit()
{
 Expression e = Expression.Constant(5, typeof(int));
 var lambda = Expression.Lambda<Func<int>>(e);
 lambda.Compile();
}

private static bool IsRunningOnAOT()
{
 try
 {
 AttemptJit();
 return false;
 }
 catch (ExecutionEngineException)
 {
 return true;
 }
}

Hope this fact that EEE can be caught is not a Mono bug (or at least, it doesn’t get fixed ;) ).

Filed under: Uncategorized

01 Oct

Moon# 0.5.0 released!

I’ve released MoonSharp 0.5.0 (Moon#) the brand new Lua interpreter written entirely in C# for the best compatibility over .NET, Mono, Unity and Xamarin versions.

Many things have changed since the plans detailed in this blog.. for the best. Check it out.

Head to http://www.moonsharp.org

 

Filed under: Uncategorized

20 May

Moon# is online!

Moon# has its own website on GitHub : https://github.com/xanathar/moonsharp

Also, if you want to peek at the current backlog: https://www.pivotaltracker.com/s/projects/1082626

 

BTW, I’m moving all my open source efforts – however weak they might be – from various sources (mainly, here or google code) to GitHub, to have everything in one place.

 

[This post has been edited, as originally the project was hosted on CodePlex]