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.Interpreter;
import org.jruby.ir.operands.IRException;
import org.jruby.ir.runtime.IRBreakJump;
import org.jruby.ir.targets.JVMVisitor;
import org.jruby.ir.targets.JVMVisitorMethodContext;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
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.ClassDefiningClassLoader;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
public class Compiler extends IRTranslator<ScriptAndCode, ClassDefiningClassLoader> {
private Compiler() {}
private static class CompilerHolder {
public static final Compiler instance = new Compiler();
}
public static Compiler getInstance() {
return CompilerHolder.instance;
}
@Override
protected ScriptAndCode execute(final Ruby runtime, final IRScriptBody scope, ClassDefiningClassLoader classLoader) {
byte[] bytecode;
MethodHandle _compiledHandle;
try {
JVMVisitor visitor = new JVMVisitor(runtime);
JVMVisitorMethodContext context = new JVMVisitorMethodContext();
bytecode = visitor.compileToBytecode(scope, context);
Class compiled = visitor.defineFromBytecode(scope, bytecode, classLoader);
Method compiledMethod = compiled.getMethod("RUBY$script", ThreadContext.class,
StaticScope.class, IRubyObject.class, IRubyObject[].class, Block.class, RubyModule.class, String.class);
_compiledHandle = MethodHandles.publicLookup().unreflect(compiledMethod);
} catch (NotCompilableException nce) {
throw nce;
} catch (Throwable t) {
throw new NotCompilableException("failed to compile script " + scope.getId(), t);
}
final MethodHandle compiledHandle = _compiledHandle;
final StaticScope staticScope = scope.getStaticScope();
Script script = new AbstractScript() {
@Override
public IRubyObject __file__(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
try {
return (IRubyObject) compiledHandle.invokeWithArguments(context, staticScope, self, IRubyObject.NULL_ARRAY, block, self.getMetaClass(), null);
} catch (Throwable t) {
Helpers.throwException(t);
return null;
}
}
@Override
public IRubyObject load(ThreadContext context, IRubyObject self, boolean wrap) {
RubyModule currModule = staticScope.getModule();
staticScope.setModule(currModule);
context.setCurrentVisibility(Visibility.PRIVATE);
try {
return (IRubyObject) compiledHandle.invokeWithArguments(context, staticScope, self, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK, currModule, null);
} catch (IRBreakJump bj) {
throw IRException.BREAK_LocalJumpError.getException(context.runtime);
} catch (Throwable t) {
Helpers.throwException(t);
return null;
} finally {
}
}
};
return new ScriptAndCode(bytecode, script);
}
}