org.jruby.RubyJRuby Maven / Gradle / Ivy
/*
**** BEGIN LICENSE BLOCK *****
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Common Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/cpl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2005 Thomas E Enebo
* Copyright (C) 2009 MenTaLguY
* Copyright (C) 2010 Charles Oliver Nutter
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the CPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the CPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby;
import org.jruby.ast.RestArgNode;
import org.jruby.ext.jruby.JRubyUtilLibrary;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.jruby.anno.JRubyMethod;
import org.jruby.anno.JRubyModule;
import org.jruby.anno.JRubyClass;
import org.jruby.ast.ArgsNode;
import org.jruby.ast.ListNode;
import org.jruby.exceptions.RaiseException;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaObject;
import org.jruby.runtime.Arity;
import org.jruby.runtime.Block;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.ast.Node;
import org.jruby.ast.types.INameNode;
import org.jruby.compiler.ASTInspector;
import org.jruby.compiler.ASTCompiler;
import org.jruby.compiler.impl.StandardASMCompiler;
import org.jruby.internal.runtime.methods.MethodArgs;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.InterpretedBlock;
import org.jruby.runtime.ThreadContext;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.TraceClassVisitor;
import java.util.Map;
import org.jruby.ast.MultipleAsgn19Node;
import org.jruby.ast.UnnamedRestArgNode;
import org.jruby.internal.runtime.methods.MethodArgs2;
import org.jruby.internal.runtime.methods.ProcMethod;
import org.jruby.java.proxies.JavaProxy;
import org.jruby.javasupport.util.RuntimeHelpers;
import org.jruby.runtime.ExecutionContext;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.util.JRubyClassLoader;
import static org.jruby.runtime.Visibility.*;
/**
* Module which defines JRuby-specific methods for use.
*/
@JRubyModule(name="JRuby")
public class RubyJRuby {
public static RubyModule createJRuby(Ruby runtime) {
ThreadContext context = runtime.getCurrentContext();
runtime.getKernel().callMethod(context, "require", runtime.newString("java"));
RubyModule jrubyModule = runtime.defineModule("JRuby");
jrubyModule.defineAnnotatedMethods(RubyJRuby.class);
jrubyModule.defineAnnotatedMethods(JRubyUtilLibrary.class);
RubyClass compiledScriptClass = jrubyModule.defineClassUnder("CompiledScript",runtime.getObject(), runtime.getObject().getAllocator());
for (String name : new String[] {"name", "class_name", "original_script", "code"}) {
compiledScriptClass.addReadWriteAttribute(context, name);
}
compiledScriptClass.defineAnnotatedMethods(JRubyCompiledScript.class);
RubyClass threadLocalClass = jrubyModule.defineClassUnder("ThreadLocal", runtime.getObject(), JRubyThreadLocal.ALLOCATOR);
threadLocalClass.defineAnnotatedMethods(JRubyExecutionContextLocal.class);
RubyClass fiberLocalClass = jrubyModule.defineClassUnder("FiberLocal", runtime.getObject(), JRubyFiberLocal.ALLOCATOR);
fiberLocalClass.defineAnnotatedMethods(JRubyExecutionContextLocal.class);
return jrubyModule;
}
public static RubyModule createJRubyExt(Ruby runtime) {
runtime.getKernel().callMethod(runtime.getCurrentContext(),"require", runtime.newString("java"));
RubyModule mJRubyExt = runtime.getOrCreateModule("JRuby").defineModuleUnder("Extensions");
mJRubyExt.defineAnnotatedMethods(JRubyExtensions.class);
runtime.getObject().includeModule(mJRubyExt);
return mJRubyExt;
}
public static void createJRubyCoreExt(Ruby runtime) {
runtime.getClassClass().defineAnnotatedMethods(JRubyClassExtensions.class);
runtime.getThread().defineAnnotatedMethods(JRubyThreadExtensions.class);
runtime.getString().defineAnnotatedMethods(JRubyStringExtensions.class);
}
public static class JRubySynchronizedMeta {
@JRubyMethod(visibility = PRIVATE)
public static IRubyObject append_features(IRubyObject self, IRubyObject target) {
if (target instanceof RubyClass && self instanceof RubyModule) { // should always be true
RubyClass targetModule = ((RubyClass)target);
targetModule.becomeSynchronized();
return ((RubyModule)self).append_features(target);
}
throw target.getRuntime().newTypeError(self + " can only be included into classes");
}
@JRubyMethod(visibility = PRIVATE)
public static IRubyObject extend_object(IRubyObject self, IRubyObject obj) {
if (self instanceof RubyModule) {
RubyClass singletonClass = obj.getSingletonClass();
singletonClass.becomeSynchronized();
return ((RubyModule)self).extend_object(obj);
}
// should never happen
throw self.getRuntime().newTypeError("JRuby::Singleton.extend_object called against " + self);
}
}
@JRubyMethod(module = true)
public static IRubyObject runtime(IRubyObject recv, Block unusedBlock) {
return JavaUtil.convertJavaToUsableRubyObject(recv.getRuntime(), recv.getRuntime());
}
@JRubyMethod(module = true)
public static IRubyObject with_current_runtime_as_global(ThreadContext context, IRubyObject recv, Block block) {
Ruby currentRuntime = context.getRuntime();
Ruby globalRuntime = Ruby.getGlobalRuntime();
try {
if (globalRuntime != currentRuntime) {
currentRuntime.useAsGlobalRuntime();
}
block.yieldSpecific(context);
} finally {
if (Ruby.getGlobalRuntime() != globalRuntime) {
globalRuntime.useAsGlobalRuntime();
}
}
return currentRuntime.getNil();
}
@JRubyMethod(name = {"parse", "ast_for"}, optional = 3, module = true)
public static IRubyObject parse(IRubyObject recv, IRubyObject[] args, Block block) {
if(block.isGiven()) {
if(block.getBody() instanceof org.jruby.runtime.CompiledBlock) {
throw new RuntimeException("Cannot compile an already compiled block. Use -J-Djruby.jit.enabled=false to avoid this problem.");
}
Arity.checkArgumentCount(recv.getRuntime(),args,0,0);
return JavaUtil.convertJavaToUsableRubyObject(recv.getRuntime(), ((InterpretedBlock)block.getBody()).getBodyNode());
} else {
Arity.checkArgumentCount(recv.getRuntime(),args,1,3);
String filename = "-";
boolean extraPositionInformation = false;
RubyString content = args[0].convertToString();
if(args.length>1) {
filename = args[1].convertToString().toString();
if(args.length>2) {
extraPositionInformation = args[2].isTrue();
}
}
return JavaUtil.convertJavaToUsableRubyObject(recv.getRuntime(),
recv.getRuntime().parse(content.getByteList(), filename, null, 0, extraPositionInformation));
}
}
@JRubyMethod(name = "compile", optional = 3, module = true)
public static IRubyObject compile(IRubyObject recv, IRubyObject[] args, Block block) {
Node node;
String filename;
RubyString content;
if(block.isGiven()) {
Arity.checkArgumentCount(recv.getRuntime(),args,0,0);
if(block.getBody() instanceof org.jruby.runtime.CompiledBlock) {
throw new RuntimeException("Cannot compile an already compiled block. Use -J-Djruby.jit.enabled=false to avoid this problem.");
}
content = RubyString.newEmptyString(recv.getRuntime());
Node bnode = ((InterpretedBlock)block.getBody()).getBodyNode();
node = new org.jruby.ast.RootNode(bnode.getPosition(), block.getBinding().getDynamicScope(), bnode);
filename = "__block_" + node.getPosition().getFile();
} else {
Arity.checkArgumentCount(recv.getRuntime(),args,1,3);
filename = "-";
boolean extraPositionInformation = false;
content = args[0].convertToString();
if(args.length>1) {
filename = args[1].convertToString().toString();
if(args.length>2) {
extraPositionInformation = args[2].isTrue();
}
}
node = recv.getRuntime().parse(content.getByteList(), filename, null, 0, extraPositionInformation);
}
String classname;
if (filename.equals("-e")) {
classname = "__dash_e__";
} else {
classname = filename.replace('\\', '/').replaceAll(".rb", "").replaceAll("-","_dash_");
}
ASTInspector inspector = new ASTInspector();
inspector.inspect(node);
StandardASMCompiler asmCompiler = new StandardASMCompiler(classname, filename);
ASTCompiler compiler = recv.getRuntime().getInstanceConfig().newCompiler();
compiler.compileRoot(node, asmCompiler, inspector);
byte[] bts = asmCompiler.getClassByteArray();
IRubyObject compiledScript = ((RubyModule)recv).fastGetConstant("CompiledScript").callMethod(recv.getRuntime().getCurrentContext(),"new");
compiledScript.callMethod(recv.getRuntime().getCurrentContext(), "name=", recv.getRuntime().newString(filename));
compiledScript.callMethod(recv.getRuntime().getCurrentContext(), "class_name=", recv.getRuntime().newString(classname));
compiledScript.callMethod(recv.getRuntime().getCurrentContext(), "original_script=", content);
compiledScript.callMethod(recv.getRuntime().getCurrentContext(), "code=", JavaUtil.convertJavaToUsableRubyObject(recv.getRuntime(), bts));
return compiledScript;
}
@JRubyMethod(name = "reference", required = 1, module = true)
public static IRubyObject reference(ThreadContext context, IRubyObject recv, IRubyObject obj) {
Ruby runtime = context.getRuntime();
return Java.getInstance(runtime, obj);
}
@JRubyMethod(name = "dereference", required = 1, module = true)
public static IRubyObject dereference(ThreadContext context, IRubyObject recv, IRubyObject obj) {
Object unwrapped;
if (obj instanceof JavaProxy) {
unwrapped = ((JavaProxy)obj).getObject();
} else if (obj.dataGetStruct() instanceof JavaObject) {
unwrapped = JavaUtil.unwrapJavaObject(obj);
} else {
throw context.getRuntime().newTypeError("got " + obj + ", expected wrapped Java object");
}
if (!(unwrapped instanceof IRubyObject)) {
throw context.getRuntime().newTypeError("got " + obj + ", expected Java-wrapped Ruby object");
}
return (IRubyObject)unwrapped;
}
@JRubyClass(name="JRuby::CompiledScript")
public static class JRubyCompiledScript {
@JRubyMethod(name = "to_s")
public static IRubyObject compiled_script_to_s(IRubyObject recv) {
return recv.getInstanceVariables().fastGetInstanceVariable("@original_script");
}
@JRubyMethod(name = "inspect")
public static IRubyObject compiled_script_inspect(IRubyObject recv) {
return recv.getRuntime().newString("#");
}
@JRubyMethod(name = "inspect_bytecode")
public static IRubyObject compiled_script_inspect_bytecode(IRubyObject recv) {
StringWriter sw = new StringWriter();
ClassReader cr = new ClassReader((byte[])recv.getInstanceVariables().fastGetInstanceVariable("@code").toJava(byte[].class));
TraceClassVisitor cv = new TraceClassVisitor(new PrintWriter(sw));
cr.accept(cv, ClassReader.SKIP_DEBUG);
return recv.getRuntime().newString(sw.toString());
}
}
public abstract static class JRubyExecutionContextLocal extends RubyObject {
private IRubyObject default_value;
private RubyProc default_proc;
public JRubyExecutionContextLocal(Ruby runtime, RubyClass type) {
super(runtime, type);
default_value = runtime.getNil();
default_proc = null;
}
@JRubyMethod(name="initialize", required=0, optional=1)
public IRubyObject rubyInitialize(ThreadContext context, IRubyObject args[], Block block) {
if (block.isGiven()) {
if (args.length != 0) {
throw context.getRuntime().newArgumentError("wrong number of arguments");
}
default_proc = block.getProcObject();
if (default_proc == null) {
default_proc = RubyProc.newProc(context.getRuntime(), block, block.type);
}
} else {
if (args.length == 1) {
default_value = args[0];
} else if (args.length != 0) {
throw context.getRuntime().newArgumentError("wrong number of arguments");
}
}
return context.getRuntime().getNil();
}
@JRubyMethod(name="default", required=0)
public IRubyObject getDefault(ThreadContext context) {
return default_value;
}
@JRubyMethod(name="default_proc", required=0)
public IRubyObject getDefaultProc(ThreadContext context) {
if (default_proc != null) {
return default_proc;
} else {
return context.getRuntime().getNil();
}
}
private static final IRubyObject[] EMPTY_ARGS = new IRubyObject[]{};
@JRubyMethod(name="value", required=0)
public IRubyObject getValue(ThreadContext context) {
final IRubyObject value;
final Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy