org.jruby.RubyClass Maven / Gradle / Ivy
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse 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/epl-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) 2001-2004 Jan Arne Petersen
* Copyright (C) 2002-2004 Anders Bengtsson
* Copyright (C) 2004-2005 Thomas E Enebo
* Copyright (C) 2004 Stefan Matthias Aust
*
* 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 EPL, 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 EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby;
import org.jruby.runtime.Arity;
import org.jruby.runtime.ivars.VariableAccessor;
import static org.jruby.util.CodegenUtils.ci;
import static org.jruby.util.CodegenUtils.p;
import static org.jruby.util.CodegenUtils.sig;
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
import static org.objectweb.asm.Opcodes.ACC_SUPER;
import static org.objectweb.asm.Opcodes.ACC_VARARGS;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.compiler.impl.SkinnyMethodAdapter;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.java.codegen.RealClassGenerator;
import org.jruby.java.codegen.Reified;
import org.jruby.javasupport.Java;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallSite;
import org.jruby.runtime.CallType;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.MethodIndex;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ObjectMarshal;
import org.jruby.runtime.ThreadContext;
import static org.jruby.runtime.Visibility.*;
import static org.jruby.CompatVersion.*;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CacheEntry;
import org.jruby.runtime.ivars.VariableAccessorField;
import org.jruby.runtime.ivars.VariableTableManager;
import org.jruby.runtime.marshal.MarshalStream;
import org.jruby.runtime.marshal.UnmarshalStream;
import org.jruby.runtime.opto.Invalidator;
import org.jruby.util.ClassCache.OneShotClassLoader;
import org.jruby.util.ClassDefiningClassLoader;
import org.jruby.util.CodegenUtils;
import org.jruby.util.JavaNameMangler;
import org.jruby.util.collections.WeakHashSet;
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
/**
*
* @author jpetersen
*/
@JRubyClass(name="Class", parent="Module")
public class RubyClass extends RubyModule {
private static final Logger LOG = LoggerFactory.getLogger("RubyClass");
public static void createClassClass(Ruby runtime, RubyClass classClass) {
classClass.index = ClassIndex.CLASS;
classClass.setReifiedClass(RubyClass.class);
classClass.kindOf = new RubyModule.JavaClassKindOf(RubyClass.class);
classClass.undefineMethod("module_function");
classClass.undefineMethod("append_features");
classClass.undefineMethod("extend_object");
classClass.defineAnnotatedMethods(RubyClass.class);
}
public static final ObjectAllocator CLASS_ALLOCATOR = new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
RubyClass clazz = new RubyClass(runtime);
clazz.allocator = ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR; // Class.allocate object is not allocatable before it is initialized
return clazz;
}
};
public ObjectAllocator getAllocator() {
return allocator;
}
public void setAllocator(ObjectAllocator allocator) {
this.allocator = allocator;
}
/**
* Set a reflective allocator that calls a no-arg constructor on the given
* class.
*
* @param cls The class on which to call the default constructor to allocate
*/
public void setClassAllocator(final Class cls) {
this.allocator = new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
try {
RubyBasicObject object = (RubyBasicObject)cls.newInstance();
object.setMetaClass(klazz);
return object;
} catch (InstantiationException ie) {
throw runtime.newTypeError("could not allocate " + cls + " with default constructor:\n" + ie);
} catch (IllegalAccessException iae) {
throw runtime.newSecurityError("could not allocate " + cls + " due to inaccessible default constructor:\n" + iae);
}
}
};
this.reifiedClass = cls;
}
/**
* Set a reflective allocator that calls the "standard" Ruby object
* constructor (Ruby, RubyClass) on the given class.
*
* @param cls The class from which to grab a standard Ruby constructor
*/
public void setRubyClassAllocator(final Class cls) {
try {
final Constructor constructor = cls.getConstructor(Ruby.class, RubyClass.class);
this.allocator = new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
try {
return (IRubyObject)constructor.newInstance(runtime, klazz);
} catch (InvocationTargetException ite) {
throw runtime.newTypeError("could not allocate " + cls + " with (Ruby, RubyClass) constructor:\n" + ite);
} catch (InstantiationException ie) {
throw runtime.newTypeError("could not allocate " + cls + " with (Ruby, RubyClass) constructor:\n" + ie);
} catch (IllegalAccessException iae) {
throw runtime.newSecurityError("could not allocate " + cls + " due to inaccessible (Ruby, RubyClass) constructor:\n" + iae);
}
}
};
this.reifiedClass = cls;
} catch (NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
}
/**
* Set a reflective allocator that calls the "standard" Ruby object
* constructor (Ruby, RubyClass) on the given class via a static
* __allocate__ method intermediate.
*
* @param cls The class from which to grab a standard Ruby __allocate__
* method.
*/
public void setRubyStaticAllocator(final Class cls) {
try {
final Method method = cls.getDeclaredMethod("__allocate__", Ruby.class, RubyClass.class);
this.allocator = new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
try {
return (IRubyObject)method.invoke(null, runtime, klazz);
} catch (InvocationTargetException ite) {
throw runtime.newTypeError("could not allocate " + cls + " with (Ruby, RubyClass) constructor:\n" + ite);
} catch (IllegalAccessException iae) {
throw runtime.newSecurityError("could not allocate " + cls + " due to inaccessible (Ruby, RubyClass) constructor:\n" + iae);
}
}
};
this.reifiedClass = cls;
} catch (NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
}
@JRubyMethod(name = "allocate")
public IRubyObject allocate() {
if (superClass == null) {
if(!(runtime.is1_9() && this == runtime.getBasicObject())) {
throw runtime.newTypeError("can't instantiate uninitialized class");
}
}
IRubyObject obj = allocator.allocate(runtime, this);
if (obj.getMetaClass().getRealClass() != getRealClass()) {
throw runtime.newTypeError("wrong instance allocation");
}
return obj;
}
public CallSite getBaseCallSite(int idx) {
return baseCallSites[idx];
}
public CallSite[] getBaseCallSites() {
return baseCallSites;
}
public CallSite[] getExtraCallSites() {
return extraCallSites;
}
public VariableTableManager getVariableTableManager() {
return variableTableManager;
}
public boolean hasObjectID() {
return variableTableManager.hasObjectID();
}
public Map getVariableAccessorsForRead() {
return variableTableManager.getVariableAccessorsForRead();
}
public VariableAccessor getVariableAccessorForWrite(String name) {
return variableTableManager.getVariableAccessorForWrite(name);
}
public VariableAccessor getVariableAccessorForRead(String name) {
VariableAccessor accessor = getVariableAccessorsForRead().get(name);
if (accessor == null) accessor = VariableAccessor.DUMMY_ACCESSOR;
return accessor;
}
public VariableAccessorField getObjectIdAccessorField() {
return variableTableManager.getObjectIdAccessorField();
}
public VariableAccessorField getNativeHandleAccessorField() {
return variableTableManager.getNativeHandleAccessorField();
}
public VariableAccessor getNativeHandleAccessorForWrite() {
return variableTableManager.getNativeHandleAccessorForWrite();
}
public VariableAccessorField getFFIHandleAccessorField() {
return variableTableManager.getFFIHandleAccessorField();
}
public VariableAccessor getFFIHandleAccessorForRead() {
return variableTableManager.getFFIHandleAccessorForRead();
}
public VariableAccessor getFFIHandleAccessorForWrite() {
return variableTableManager.getFFIHandleAccessorForWrite();
}
public VariableAccessorField getObjectGroupAccessorField() {
return variableTableManager.getObjectGroupAccessorField();
}
public VariableAccessor getObjectGroupAccessorForRead() {
return variableTableManager.getObjectGroupAccessorForRead();
}
public VariableAccessor getObjectGroupAccessorForWrite() {
return variableTableManager.getObjectGroupAccessorForWrite();
}
public int getVariableTableSize() {
return variableTableManager.getVariableTableSize();
}
public int getVariableTableSizeWithExtras() {
return variableTableManager.getVariableTableSizeWithExtras();
}
/**
* Get an array of all the known instance variable names. The offset into
* the array indicates the offset of the variable's value in the per-object
* variable array.
*
* @return a copy of the array of known instance variable names
*/
public String[] getVariableNames() {
return variableTableManager.getVariableNames();
}
public Map getVariableTableCopy() {
return new HashMap(getVariableAccessorsForRead());
}
@Override
public int getNativeTypeIndex() {
return ClassIndex.CLASS;
}
@Override
public boolean isModule() {
return false;
}
@Override
public boolean isClass() {
return true;
}
@Override
public boolean isSingleton() {
return false;
}
/** boot_defclass
* Create an initial Object meta class before Module and Kernel dependencies have
* squirreled themselves together.
*
* @param runtime we need it
* @return a half-baked meta class for object
*/
public static RubyClass createBootstrapClass(Ruby runtime, String name, RubyClass superClass, ObjectAllocator allocator) {
RubyClass obj;
if (superClass == null ) { // boot the Object class
obj = new RubyClass(runtime);
obj.marshal = DEFAULT_OBJECT_MARSHAL;
} else { // boot the Module and Class classes
obj = new RubyClass(runtime, superClass);
}
obj.setAllocator(allocator);
obj.setBaseName(name);
return obj;
}
/** separate path for MetaClass and IncludedModuleWrapper construction
* (rb_class_boot version for MetaClasses)
* no marshal, allocator initialization and addSubclass(this) here!
*/
protected RubyClass(Ruby runtime, RubyClass superClass, boolean objectSpace) {
super(runtime, runtime.getClassClass(), objectSpace);
this.runtime = runtime;
// Since this path is for included wrappers and singletons, use parent
// class's realClass and varTableMgr. If the latter is null, create a
// dummy, since we won't be using it anyway (we're above BasicObject
// so variable requests won't reach us).
if (superClass == null) {
this.realClass = null;
this.variableTableManager = new VariableTableManager(this);
} else {
this.realClass = superClass.realClass;
if (realClass != null) {
this.variableTableManager = realClass.variableTableManager;
} else {
this.variableTableManager = new VariableTableManager(this);
}
}
setSuperClass(superClass); // this is the only case it might be null here (in MetaClass construction)
}
/** used by CLASS_ALLOCATOR (any Class' class will be a Class!)
* also used to bootstrap Object class
*/
protected RubyClass(Ruby runtime) {
super(runtime, runtime.getClassClass());
this.runtime = runtime;
this.realClass = this;
this.variableTableManager = new VariableTableManager(this);
index = ClassIndex.CLASS;
}
/** rb_class_boot (for plain Classes)
* also used to bootstrap Module and Class classes
*/
protected RubyClass(Ruby runtime, RubyClass superClazz) {
this(runtime);
setSuperClass(superClazz);
marshal = superClazz.marshal; // use parent's marshal
superClazz.addSubclass(this);
allocator = superClazz.allocator;
infectBy(superClass);
}
/**
* A constructor which allows passing in an array of supplementary call sites.
*/
protected RubyClass(Ruby runtime, RubyClass superClazz, CallSite[] extraCallSites) {
this(runtime);
setSuperClass(superClazz);
this.marshal = superClazz.marshal; // use parent's marshal
superClazz.addSubclass(this);
this.extraCallSites = extraCallSites;
infectBy(superClass);
}
/**
* Construct a new class with the given name scoped under Object (global)
* and with Object as its immediate superclass.
* Corresponds to rb_class_new in MRI.
*/
public static RubyClass newClass(Ruby runtime, RubyClass superClass) {
if (superClass == runtime.getClassClass()) throw runtime.newTypeError("can't make subclass of Class");
if (superClass.isSingleton()) throw runtime.newTypeError("can't make subclass of virtual class");
return new RubyClass(runtime, superClass);
}
/**
* A variation on newClass that allow passing in an array of supplementary
* call sites to improve dynamic invocation.
*/
public static RubyClass newClass(Ruby runtime, RubyClass superClass, CallSite[] extraCallSites) {
if (superClass == runtime.getClassClass()) throw runtime.newTypeError("can't make subclass of Class");
if (superClass.isSingleton()) throw runtime.newTypeError("can't make subclass of virtual class");
return new RubyClass(runtime, superClass, extraCallSites);
}
/**
* Construct a new class with the given name, allocator, parent class,
* and containing class. If setParent is true, the class's parent will be
* explicitly set to the provided parent (rather than the new class just
* being assigned to a constant in that parent).
* Corresponds to rb_class_new/rb_define_class_id/rb_name_class/rb_set_class_path
* in MRI.
*/
public static RubyClass newClass(Ruby runtime, RubyClass superClass, String name, ObjectAllocator allocator, RubyModule parent, boolean setParent) {
RubyClass clazz = newClass(runtime, superClass);
clazz.setBaseName(name);
clazz.setAllocator(allocator);
clazz.makeMetaClass(superClass.getMetaClass());
if (setParent) clazz.setParent(parent);
parent.setConstant(name, clazz);
clazz.inherit(superClass);
return clazz;
}
/**
* A variation on newClass that allows passing in an array of supplementary
* call sites to improve dynamic invocation performance.
*/
public static RubyClass newClass(Ruby runtime, RubyClass superClass, String name, ObjectAllocator allocator, RubyModule parent, boolean setParent, CallSite[] extraCallSites) {
RubyClass clazz = newClass(runtime, superClass, extraCallSites);
clazz.setBaseName(name);
clazz.setAllocator(allocator);
clazz.makeMetaClass(superClass.getMetaClass());
if (setParent) clazz.setParent(parent);
parent.setConstant(name, clazz);
clazz.inherit(superClass);
return clazz;
}
/** rb_make_metaclass
*
*/
@Override
public RubyClass makeMetaClass(RubyClass superClass) {
if (isSingleton()) { // could be pulled down to RubyClass in future
MetaClass klass = new MetaClass(runtime, superClass, this); // rb_class_boot
setMetaClass(klass);
klass.setMetaClass(klass);
klass.setSuperClass(getSuperClass().getRealClass().getMetaClass());
return klass;
} else {
return super.makeMetaClass(superClass);
}
}
@Deprecated
public IRubyObject invoke(ThreadContext context, IRubyObject self, int methodIndex, String name, IRubyObject[] args, CallType callType, Block block) {
return invoke(context, self, name, args, callType, block);
}
public boolean notVisibleAndNotMethodMissing(DynamicMethod method, String name, IRubyObject caller, CallType callType) {
return !method.isCallableFrom(caller, callType) && !name.equals("method_missing");
}
public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
CallType callType, Block block) {
DynamicMethod method = searchMethod(name);
IRubyObject caller = context.getFrameSelf();
if (shouldCallMethodMissing(method, name, caller, callType)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, callType, block);
}
return method.call(context, self, this, name, block);
}
public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name, Block block) {
DynamicMethod method = searchMethod(name);
if (shouldCallMethodMissing(method)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, CallType.FUNCTIONAL, block);
}
return method.call(context, self, this, name, block);
}
public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
IRubyObject[] args, CallType callType, Block block) {
assert args != null;
DynamicMethod method = searchMethod(name);
IRubyObject caller = context.getFrameSelf();
if (shouldCallMethodMissing(method, name, caller, callType)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, callType, args, block);
}
return method.call(context, self, this, name, args, block);
}
public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
IRubyObject[] args, Block block) {
assert args != null;
DynamicMethod method = searchMethod(name);
if (shouldCallMethodMissing(method)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, CallType.FUNCTIONAL, args, block);
}
return method.call(context, self, this, name, args, block);
}
public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg, CallType callType, Block block) {
DynamicMethod method = searchMethod(name);
IRubyObject caller = context.getFrameSelf();
if (shouldCallMethodMissing(method, name, caller, callType)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, callType, arg, block);
}
return method.call(context, self, this, name, arg, block);
}
public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg, Block block) {
DynamicMethod method = searchMethod(name);
if (shouldCallMethodMissing(method)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, CallType.FUNCTIONAL, arg, block);
}
return method.call(context, self, this, name, arg, block);
}
public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg0, IRubyObject arg1, CallType callType, Block block) {
DynamicMethod method = searchMethod(name);
IRubyObject caller = context.getFrameSelf();
if (shouldCallMethodMissing(method, name, caller, callType)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, callType, arg0, arg1, block);
}
return method.call(context, self, this, name, arg0, arg1, block);
}
public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg0, IRubyObject arg1, Block block) {
DynamicMethod method = searchMethod(name);
if (shouldCallMethodMissing(method)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, CallType.FUNCTIONAL, arg0, arg1, block);
}
return method.call(context, self, this, name, arg0, arg1, block);
}
public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, CallType callType, Block block) {
DynamicMethod method = searchMethod(name);
IRubyObject caller = context.getFrameSelf();
if (shouldCallMethodMissing(method, name, caller, callType)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, callType, arg0, arg1, arg2, block);
}
return method.call(context, self, this, name, arg0, arg1, arg2, block);
}
public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) {
DynamicMethod method = searchMethod(name);
if (shouldCallMethodMissing(method)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, CallType.FUNCTIONAL, arg0, arg1, arg2, block);
}
return method.call(context, self, this, name, arg0, arg1, arg2, block);
}
public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
CallType callType) {
DynamicMethod method = searchMethod(name);
IRubyObject caller = context.getFrameSelf();
if (shouldCallMethodMissing(method, name, caller, callType)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, callType, Block.NULL_BLOCK);
}
return method.call(context, self, this, name);
}
public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name) {
DynamicMethod method = searchMethod(name);
if (shouldCallMethodMissing(method)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, CallType.FUNCTIONAL, Block.NULL_BLOCK);
}
return method.call(context, self, this, name);
}
public IRubyObject finvokeChecked(ThreadContext context, IRubyObject self, String name) {
RubyClass klass = self.getMetaClass();
DynamicMethod me;
if (!checkFuncallRespondTo(context, self.getMetaClass(), self, name))
return null;
me = searchMethod(name);
if (!checkFuncallCallable(context, me, CallType.FUNCTIONAL, self)) {
return checkFuncallMissing(context, klass, self, name);
}
return me.call(context, self, klass, name);
}
// MRI: check_funcall_exec
private static IRubyObject checkFuncallExec(ThreadContext context, IRubyObject self, String name, IRubyObject... args) {
IRubyObject[] newArgs = new IRubyObject[args.length + 1];
System.arraycopy(args, 0, newArgs, 1, args.length);
newArgs[0] = context.runtime.newSymbol(name);
return self.callMethod(context, "method_missing", newArgs);
}
// MRI: check_funcall_failed
private static IRubyObject checkFuncallFailed(ThreadContext context, IRubyObject self, String name, RubyClass expClass, IRubyObject... args) {
if (self.respondsTo(name)) {
throw context.runtime.newRaiseException(expClass, name);
}
return null;
}
// MRI: check_funcall_respond_to
private static boolean checkFuncallRespondTo(ThreadContext context, RubyClass klass, IRubyObject recv, String mid) {
Ruby runtime = context.runtime;
RubyClass defined_class;
DynamicMethod me = klass.searchMethod("respond_to?");
// NOTE: isBuiltin here would be NOEX_BASIC in MRI, a flag only added to respond_to?, method_missing, and
// respond_to_missing? Same effect, I believe.
if (me != null && !me.isUndefined() && !me.isBuiltin()) {
Arity arity = me.getArity();
if (arity.getValue() > 2)
throw runtime.newArgumentError("respond_to? must accept 1 or 2 arguments (requires " + arity + ")");
IRubyObject result = me.call(context, recv, klass, "respond_to?", runtime.newString(mid), runtime.getTrue());
if (!result.isTrue()) {
return false;
}
}
return true;
}
// MRI: check_funcall_callable
public static boolean checkFuncallCallable(ThreadContext context, DynamicMethod method, CallType callType, IRubyObject self) {
return rbMethodCallStatus(context, method, callType, self);
}
// MRI: rb_method_call_status
// FIXME: Partial impl because we don't have these "NOEX" flags
public static boolean rbMethodCallStatus(ThreadContext context, DynamicMethod method, CallType callType, IRubyObject self) {
return method != null && !method.isUndefined() && method.isCallableFrom(self, callType);
}
private static IRubyObject checkFuncallMissing(ThreadContext context, RubyClass klass, IRubyObject self, String method, IRubyObject... args) {
Ruby runtime = context.runtime;
if (klass.isMethodBuiltin("method_missing")) {
return null;
}
else {
final IRubyObject $ex = context.getErrorInfo();
try {
return checkFuncallExec(context, self, method, args);
}
catch (RaiseException e) {
context.setErrorInfo($ex); // restore $!
return checkFuncallFailed(context, self, method, runtime.getNoMethodError(), args);
}
}
}
public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
IRubyObject[] args, CallType callType) {
assert args != null;
DynamicMethod method = searchMethod(name);
IRubyObject caller = context.getFrameSelf();
if (shouldCallMethodMissing(method, name, caller, callType)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, callType, args, Block.NULL_BLOCK);
}
return method.call(context, self, this, name, args);
}
public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
IRubyObject[] args) {
assert args != null;
DynamicMethod method = searchMethod(name);
if (shouldCallMethodMissing(method)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, CallType.FUNCTIONAL, args, Block.NULL_BLOCK);
}
return method.call(context, self, this, name, args);
}
public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg, CallType callType) {
DynamicMethod method = searchMethod(name);
IRubyObject caller = context.getFrameSelf();
if (shouldCallMethodMissing(method, name, caller, callType)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, callType, arg, Block.NULL_BLOCK);
}
return method.call(context, self, this, name, arg);
}
public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg) {
DynamicMethod method = searchMethod(name);
if (shouldCallMethodMissing(method)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, CallType.FUNCTIONAL, arg, Block.NULL_BLOCK);
}
return method.call(context, self, this, name, arg);
}
public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg0, IRubyObject arg1, CallType callType) {
DynamicMethod method = searchMethod(name);
IRubyObject caller = context.getFrameSelf();
if (shouldCallMethodMissing(method, name, caller, callType)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, callType, arg0, arg1, Block.NULL_BLOCK);
}
return method.call(context, self, this, name, arg0, arg1);
}
public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg0, IRubyObject arg1) {
DynamicMethod method = searchMethod(name);
if (shouldCallMethodMissing(method)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, CallType.FUNCTIONAL, arg0, arg1, Block.NULL_BLOCK);
}
return method.call(context, self, this, name, arg0, arg1);
}
public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, CallType callType) {
DynamicMethod method = searchMethod(name);
IRubyObject caller = context.getFrameSelf();
if (shouldCallMethodMissing(method, name, caller, callType)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, callType, arg0, arg1, arg2, Block.NULL_BLOCK);
}
return method.call(context, self, this, name, arg0, arg1, arg2);
}
public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
DynamicMethod method = searchMethod(name);
if (shouldCallMethodMissing(method)) {
return Helpers.callMethodMissing(context, self, method.getVisibility(), name, CallType.FUNCTIONAL, arg0, arg1, arg2, Block.NULL_BLOCK);
}
return method.call(context, self, this, name, arg0, arg1, arg2);
}
private void dumpReifiedClass(String dumpDir, String javaPath, byte[] classBytes) {
if (dumpDir != null) {
if (dumpDir.equals("")) {
dumpDir = ".";
}
java.io.FileOutputStream classStream = null;
try {
java.io.File classFile = new java.io.File(dumpDir, javaPath + ".class");
classFile.getParentFile().mkdirs();
classStream = new java.io.FileOutputStream(classFile);
classStream.write(classBytes);
} catch (IOException io) {
getRuntime().getWarnings().warn("unable to dump class file: " + io.getMessage());
} finally {
if (classStream != null) {
try {
classStream.close();
} catch (IOException ignored) {
}
}
}
}
}
private void generateMethodAnnotations(Map> methodAnnos, SkinnyMethodAdapter m, List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy