// fields to hold Ruby and RubyClass references
cw.visitField(ACC_STATIC | ACC_PRIVATE, "ruby", ci(Ruby.class), null, null);
cw.visitField(ACC_STATIC | ACC_PRIVATE, "rubyClass", ci(RubyClass.class), null, null);
// static initializing method
SkinnyMethodAdapter m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_STATIC, "clinit", sig(void.class, Ruby.class, RubyClass.class), null, null);
m.start();
m.aload(0);
m.putstatic(javaPath, "ruby", ci(Ruby.class));
m.aload(1);
m.putstatic(javaPath, "rubyClass", ci(RubyClass.class));
m.voidreturn();
m.end();
// standard constructor that accepts Ruby, RubyClass
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC, "<init>", sig(void.class, Ruby.class, RubyClass.class), null, null);
m.aload(0);
m.aload(1);
m.aload(2);
m.invokespecial(p(reifiedParent), "<init>", sig(void.class, Ruby.class, RubyClass.class));
m.voidreturn();
m.end();
// no-arg constructor using static references to Ruby and RubyClass
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC, "<init>", CodegenUtils.sig(void.class), null, null);
m.aload(0);
m.getstatic(javaPath, "ruby", ci(Ruby.class));
m.getstatic(javaPath, "rubyClass", ci(RubyClass.class));
m.invokespecial(p(reifiedParent), "<init>", sig(void.class, Ruby.class, RubyClass.class));
m.voidreturn();
m.end();
// define fields
for (Map.Entry<String, Class> fieldSignature : getFieldSignatures().entrySet()) {
String fieldName = fieldSignature.getKey();
Class type = fieldSignature.getValue();
Map<Class, Map<String, Object>> fieldAnnos = getFieldAnnotations().get(fieldName);
FieldVisitor fieldVisitor = cw.visitField(ACC_PUBLIC, fieldName, ci(type), null, null);
if (fieldAnnos == null) {
continue;
}
for (Map.Entry<Class, Map<String, Object>> fieldAnno : fieldAnnos.entrySet()) {
Class annoType = fieldAnno.getKey();
AnnotationVisitor av = fieldVisitor.visitAnnotation(ci(annoType), true);
CodegenUtils.visitAnnotationFields(av, fieldAnno.getValue());
}
fieldVisitor.visitEnd();
}
// gather a list of instance methods, so we don't accidentally make static ones that conflict
Set<String> instanceMethods = new HashSet<String>();
// define instance methods
for (Map.Entry<String,DynamicMethod> methodEntry : getMethods().entrySet()) {
String methodName = methodEntry.getKey();
if (!JavaNameMangler.willMethodMangleOk(methodName)) continue;
String javaMethodName = JavaNameMangler.mangleMethodName(methodName);
Map<Class,Map<String,Object>> methodAnnos = getMethodAnnotations().get(methodName);
List<Map<Class,Map<String,Object>>> parameterAnnos = getParameterAnnotations().get(methodName);
Class[] methodSignature = getMethodSignatures().get(methodName);
String signature;
if (methodSignature == null) {
// non-signature signature with just IRubyObject
switch (methodEntry.getValue().getArity().getValue()) {
case 0:
signature = sig(IRubyObject.class);
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS, javaMethodName, signature, null, null);
generateMethodAnnotations(methodAnnos, m, parameterAnnos);
m.aload(0);
m.ldc(methodName);
m.invokevirtual(javaPath, "callMethod", sig(IRubyObject.class, String.class));
break;
default:
signature = sig(IRubyObject.class, IRubyObject[].class);
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS, javaMethodName, signature, null, null);
generateMethodAnnotations(methodAnnos, m, parameterAnnos);
m.aload(0);
m.ldc(methodName);
m.aload(1);
m.invokevirtual(javaPath, "callMethod", sig(IRubyObject.class, String.class, IRubyObject[].class));
}
m.areturn();
} else {
// generate a real method signature for the method, with to/from coercions
// indices for temp values
Class[] params = new Class[methodSignature.length - 1];
System.arraycopy(methodSignature, 1, params, 0, params.length);
int baseIndex = 1;
for (Class paramType : params) {
if (paramType == double.class || paramType == long.class) {
baseIndex += 2;
} else {
baseIndex += 1;
}
}
int rubyIndex = baseIndex;
signature = sig(methodSignature[0], params);
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS, javaMethodName, signature, null, null);
generateMethodAnnotations(methodAnnos, m, parameterAnnos);
m.getstatic(javaPath, "ruby", ci(Ruby.class));
m.astore(rubyIndex);
m.aload(0); // self
m.ldc(methodName); // method name
RealClassGenerator.coerceArgumentsToRuby(m, params, rubyIndex);
m.invokevirtual(javaPath, "callMethod", sig(IRubyObject.class, String.class, IRubyObject[].class));
RealClassGenerator.coerceResultAndReturn(m, methodSignature[0]);
}
if (DEBUG_REIFY) LOG.debug("defining {}#{} as {}#{}", getName(), methodName, javaName, javaMethodName + signature);
instanceMethods.add(javaMethodName + signature);
m.end();
}
// define class/static methods
for (Map.Entry<String,DynamicMethod> methodEntry : getMetaClass().getMethods().entrySet()) {
String methodName = methodEntry.getKey();
if (!JavaNameMangler.willMethodMangleOk(methodName)) continue;
String javaMethodName = JavaNameMangler.mangleMethodName(methodName);
Map<Class,Map<String,Object>> methodAnnos = getMetaClass().getMethodAnnotations().get(methodName);
List<Map<Class,Map<String,Object>>> parameterAnnos = getMetaClass().getParameterAnnotations().get(methodName);
Class[] methodSignature = getMetaClass().getMethodSignatures().get(methodName);
String signature;
if (methodSignature == null) {
// non-signature signature with just IRubyObject
switch (methodEntry.getValue().getArity().getValue()) {
case 0:
signature = sig(IRubyObject.class);
if (instanceMethods.contains(javaMethodName + signature)) continue;
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS | ACC_STATIC, javaMethodName, signature, null, null);
generateMethodAnnotations(methodAnnos, m, parameterAnnos);
m.getstatic(javaPath, "rubyClass", ci(RubyClass.class));
//m.invokevirtual("org/jruby/RubyClass", "getMetaClass", sig(RubyClass.class) );
m.ldc(methodName); // Method name
m.invokevirtual("org/jruby/RubyClass", "callMethod", sig(IRubyObject.class, String.class) );
break;
default:
signature = sig(IRubyObject.class, IRubyObject[].class);
if (instanceMethods.contains(javaMethodName + signature)) continue;
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS | ACC_STATIC, javaMethodName, signature, null, null);
generateMethodAnnotations(methodAnnos, m, parameterAnnos);
m.getstatic(javaPath, "rubyClass", ci(RubyClass.class));
m.ldc(methodName); // Method name
m.aload(0);
m.invokevirtual("org/jruby/RubyClass", "callMethod", sig(IRubyObject.class, String.class, IRubyObject[].class) );
}
m.areturn();
} else {
// generate a real method signature for the method, with to/from coercions
// indices for temp values
Class[] params = new Class[methodSignature.length - 1];
System.arraycopy(methodSignature, 1, params, 0, params.length);
int baseIndex = 0;
for (Class paramType : params) {
if (paramType == double.class || paramType == long.class) {
baseIndex += 2;
} else {
baseIndex += 1;
}
}
int rubyIndex = baseIndex;
signature = sig(methodSignature[0], params);
if (instanceMethods.contains(javaMethodName + signature)) continue;
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS | ACC_STATIC, javaMethodName, signature, null, null);
generateMethodAnnotations(methodAnnos, m, parameterAnnos);
m.getstatic(javaPath, "ruby", ci(Ruby.class));
m.astore(rubyIndex);
m.getstatic(javaPath, "rubyClass", ci(RubyClass.class));
m.ldc(methodName); // method name
RealClassGenerator.coerceArgumentsToRuby(m, params, rubyIndex);
m.invokevirtual("org/jruby/RubyClass", "callMethod", sig(IRubyObject.class, String.class, IRubyObject[].class));
RealClassGenerator.coerceResultAndReturn(m, methodSignature[0]);
}
if (DEBUG_REIFY) LOG.debug("defining {}.{} as {}.{}", getName(), methodName, javaName, javaMethodName + signature);
m.end();
}
cw.visitEnd();
byte[] classBytes = cw.toByteArray();