Compiler.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jruby.ir;
import org.jruby.Ruby;
import org.jruby.RubyModule;
import org.jruby.ast.executable.AbstractScript;
import org.jruby.ast.executable.Script;
import org.jruby.ast.executable.ScriptAndCode;
import org.jruby.compiler.NotCompilableException;
import org.jruby.ir.interpreter.BeginEndInterpreterContext;
import org.jruby.ir.operands.IRException;
import org.jruby.ir.runtime.IRBreakJump;
import org.jruby.ir.targets.JVMVisitor;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ClassDefininngJRubyClassLoader;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Compiler extends IRTranslator<ScriptAndCode, ClassDefininngJRubyClassLoader> {
// Compiler is singleton
private Compiler() {}
private static class CompilerHolder {
// FIXME: Remove as singleton unless lifus does later
public static final Compiler instance = new Compiler();
}
public static Compiler getInstance() {
return CompilerHolder.instance;
}
@Override
protected ScriptAndCode execute(final Ruby runtime, final IRScriptBody scope, ClassDefininngJRubyClassLoader classLoader) {
JVMVisitor visitor;
byte[] bytecode;
Class compiled;
MethodHandle _compiledHandle;
try {
visitor = new JVMVisitor();
bytecode = visitor.compileToBytecode(scope);
compiled = visitor.defineFromBytecode(scope, bytecode, classLoader);
Method compiledMethod = compiled.getMethod("__script__", ThreadContext.class,
StaticScope.class, IRubyObject.class, IRubyObject[].class, Block.class, RubyModule.class);
_compiledHandle = MethodHandles.publicLookup().unreflect(compiledMethod);
} catch (NotCompilableException nce) {
throw nce;
} catch (Throwable t) {
throw new NotCompilableException("failed to compile script " + scope.getName(), t);
}
final MethodHandle compiledHandle = _compiledHandle;
Script script = new AbstractScript() {
@Override
public IRubyObject __file__(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
try {
return (IRubyObject) compiledHandle.invokeWithArguments(context, scope.getStaticScope(), self, IRubyObject.NULL_ARRAY, block, self.getMetaClass());
} catch (Throwable t) {
Helpers.throwException(t);
return null; // not reached
}
}
@Override
public IRubyObject load(ThreadContext context, IRubyObject self, boolean wrap) {
// Compiler does not support BEGIN/END yet and should fail to compile above
{
// BeginEndInterpreterContext ic = (BeginEndInterpreterContext) irScope.prepareForInterpretation();
// We get the live object ball rolling here.
// This give a valid value for the top of this lexical tree.
// All new scopes can then retrieve and set based on lexical parent.
// StaticScope scope = ic.getStaticScope();
}
// Copied from Interpreter
StaticScope sscope = scope.getStaticScope();
RubyModule currModule = sscope.getModule();
if (currModule == null) {
// SSS FIXME: Looks like this has to do with Kernel#load
// and the wrap parameter. Figure it out and document it here.
currModule = context.getRuntime().getObject();
}
sscope.setModule(currModule);
DynamicScope tlbScope = scope.getToplevelScope();
if (tlbScope == null) {
context.preMethodScopeOnly(sscope);
} else {
sscope = tlbScope.getStaticScope();
context.preScopedBody(tlbScope);
tlbScope.growIfNeeded();
}
context.setCurrentVisibility(Visibility.PRIVATE);
try {
// runBeginEndBlocks(ic.getBeginBlocks(), context, self, scope, null);
return (IRubyObject) compiledHandle.invokeWithArguments(context, sscope, self, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK, currModule);
} catch (IRBreakJump bj) {
throw IRException.BREAK_LocalJumpError.getException(context.runtime);
} catch (Throwable t) {
Helpers.throwException(t);
return null; // not reached
} finally {
// runEndBlocks(ic.getEndBlocks(), context, self, scope, null);
context.popScope();
}
}
};
return new ScriptAndCode(bytecode, script);
}
}