Skip to content

Commit

Permalink
Implemented serialization of EFunHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardw committed Jun 21, 2011
1 parent 16abd1b commit e0a132b
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 43 deletions.
52 changes: 43 additions & 9 deletions src/main/java/erjang/EFun.java
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,11 @@ static byte[] gen_fun_class_data(int arity) {
return data;
}

static Map<Integer, Constructor<? extends EFun>> handlers = new HashMap<Integer, Constructor<? extends EFun>>();
static Map<String, Constructor<? extends EFun>> handlers = new HashMap<String, Constructor<? extends EFun>>();

public static EFun get_fun_with_handler(int arity, EFunHandler handler, ClassLoader loader) {
Constructor<? extends EFun> h = handlers.get(arity);
public static EFun get_fun_with_handler(String module, String function, int arity, EFunHandler handler, ClassLoader loader) {
String signature = module + function + arity;
Constructor<? extends EFun> h = handlers.get(signature);

if (h == null) {

Expand All @@ -285,24 +286,37 @@ public static EFun get_fun_with_handler(int arity, EFunHandler handler, ClassLoa
super_class_name, null);

// create handler field
FieldVisitor fv = cw.visitField(ACC_PRIVATE, "handler",
EFUNHANDLER_TYPE.getDescriptor(), null, null);
fv.visitEnd();
cw.visitField(ACC_PRIVATE, "handler", EFUNHANDLER_TYPE.getDescriptor(), null, null)
.visitEnd();
cw.visitField(ACC_PRIVATE | ACC_FINAL, "module_name", EATOM_DESC, null, null)
.visitEnd();
cw.visitField(ACC_PRIVATE | ACC_FINAL, "function_name", EATOM_DESC, null, null)
.visitEnd();


// make constructor
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "("
+ EFUNHANDLER_TYPE.getDescriptor() + ")V", null, null);
mv.visitCode();

mv.visitVarInsn(ALOAD, 0);
mv
.visitMethodInsn(INVOKESPECIAL, super_class_name, "<init>",
mv.visitMethodInsn(INVOKESPECIAL, super_class_name, "<init>",
"()V");

mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, self_type, "handler", EFUNHANDLER_TYPE
.getDescriptor());
mv.visitVarInsn(ALOAD, 0);
mv.visitLdcInsn(module);
mv.visitMethodInsn(INVOKESTATIC, EATOM_TYPE.getInternalName(),
"intern", "(Ljava/lang/String;)Lerjang/EAtom;");
mv.visitFieldInsn(PUTFIELD, self_type, "module_name", EATOM_DESC);
mv.visitVarInsn(ALOAD, 0);
mv.visitLdcInsn(function);
mv.visitMethodInsn(INVOKESTATIC, EATOM_TYPE.getInternalName(),
"intern", "(Ljava/lang/String;)Lerjang/EAtom;");
mv.visitFieldInsn(PUTFIELD, self_type, "function_name", EATOM_DESC);

mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
Expand All @@ -322,6 +336,7 @@ public static EFun get_fun_with_handler(int arity, EFunHandler handler, ClassLoa
//CompilerVisitor.make_invoketail_method(cw, self_type, arity, 0);
make_invoke_method(cw, self_type, arity);
make_go_method(cw, self_type, arity);
make_encode_method(cw, self_type, arity);

cw.visitEnd();
byte[] data = cw.toByteArray();
Expand All @@ -336,7 +351,7 @@ public static EFun get_fun_with_handler(int arity, EFunHandler handler, ClassLoa
throw new Error(e);
}

handlers.put(arity, h);
handlers.put(signature, h);
}

try {
Expand Down Expand Up @@ -460,6 +475,25 @@ private static void make_invoke_method(ClassWriter cw, String self_type,
mv.visitMaxs(arity + 2, arity + 2);
mv.visitEnd();
}

static void make_encode_method(ClassWriter cw, String className, int arity) {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "encode", "("+ Type.getDescriptor(EOutputStream.class) +")V", null, null);
mv.visitCode();

mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, className, "module_name", EATOM_DESC);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, className, "function_name", EATOM_DESC);
mv.visitLdcInsn(new Integer(arity));

mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(EOutputStream.class), "write_external_fun",
"("+EATOM_DESC+EATOM_DESC+"I)V");

mv.visitInsn(RETURN);
mv.visitMaxs(4, 1);
mv.visitEnd();
}
/*^^^^^^^^^^^^^^^^^^^^ Code generation of EFun{arity} ^^^^^^^^^^^^^^^^^^*/

/*==================== Code generation of EFun{arity}Exported: ==========*/
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/erjang/EModuleManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private EFun getFunErrorHandler() {
}

private EFun makeErrorHandler() {
return EFun.get_fun_with_handler(fun.arity,
return EFun.get_fun_with_handler(fun.module.toString(), fun.function.toString(), fun.arity,
new EFunHandler() {

@Override
Expand Down Expand Up @@ -351,7 +351,7 @@ public EFun resolve(EPID pid, EBinary md5, int index, final int old_uniq, final

if (maker == null || !md5.equals(module_md5)) {
LocalFunID fid = new LocalFunID(module, ERT.am_undefined, arity, old_index, index, old_uniq, md5);
return EFun.get_fun_with_handler(0, new EFunHandler() {
return EFun.get_fun_with_handler(this.module.toString(), "badfun", 0, new EFunHandler() {
@Override
public EObject invoke(EProc proc, EObject[] args) throws Pausable {
throw new ErlangError(am_badfun, args);
Expand All @@ -375,7 +375,7 @@ public EFun resolve(final EPID pid, final int old_uniq, final int old_index, fin

if (maker==null) {
LocalFunID fid = new LocalFunID(module, ERT.am_undef, 0, old_index, 0, old_uniq, empty_md5);
return EFun.get_fun_with_handler(0, new EFunHandler() {
return EFun.get_fun_with_handler(module.toString(), "badfun", 0, new EFunHandler() {
@Override
public EObject invoke(EProc proc, EObject[] args) throws Pausable {
throw new ErlangError(am_badfun, args);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/erjang/ERT.java
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ public static EFun resolve_fun(EObject mod, EObject fun, int arity) {

final EFun pfun = EModuleManager.resolve(new FunID(pmod, f, arity+1));

return EFun.get_fun_with_handler(arity, new EFunHandler() {
return EFun.get_fun_with_handler(m.toString(), f.toString(), arity, new EFunHandler() {
@Override
public EObject invoke(EProc proc, EObject[] args) throws Pausable {
EObject[] real_args = new EObject[args.length+1];
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/erjang/beam/interpreter/Interpreter.template
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public class Interpreter extends AbstractInterpreter {
int j=0;
for (FunIDWithEntry fi : exports) {
log.finer("INT| Export #"+(j++)+": "+fi);
EFun fun = EFun.get_fun_with_handler(fi.arity, new Function(fi.start_pc), getModuleClassLoader());
EFun fun = EFun.get_fun_with_handler(fi.module.toString(), fi.function.toString(), fi.arity, new Function(fi.start_pc), getModuleClassLoader());
EModuleManager.add_export(this, fi, fun);
}

Expand Down Expand Up @@ -268,7 +268,7 @@ public class Interpreter extends AbstractInterpreter {
#INTERPRET<-REGS_AS_SEQ(arity) xregsSeq(reg,arity)#
#INTERPRET<-REGS_AS_ARRAY(arity) xregsArray(reg,arity)#
#INTERPRET<-LOCAL_CALL(keep,label) invoke_local(proc, reg, keep,label)#
#INTERPRET<-MAKE_CLOSURE(env,arity,label) (EFun.get_fun_with_handler(arity, new Closure(env, label), getModuleClassLoader()))#
#INTERPRET<-MAKE_CLOSURE(env,arity,label) (EFun.get_fun_with_handler("erlang", "make_fun2", arity, new Closure(env, label), getModuleClassLoader()))#
#INTERPRET<-MAKE_EXH_LINK(new_exh_pc, is_try) (is_try ? new TryExceptionHandler(new_exh_pc, exh) : new CatchExceptionHandler(new_exh_pc, exh))#
#INTERPRET<-RESTORE_EXH(exh_elm) {exh = (ExceptionHandlerStackElement) exh_elm;}#

Expand Down
58 changes: 30 additions & 28 deletions src/main/java/erjang/m/java/JavaObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,18 @@ public EFun testFunction2(int nargs) {
/** a java.lang.Runnable can be used as a function of 0 arguments */
if ((nargs == 0) && (real_object instanceof Runnable)) {
final Runnable r = (Runnable) real_object;
return EFun.get_fun_with_handler(0, new EFunHandler() {
@Override
public EObject invoke(EProc proc, EObject[] args)
throws Pausable {
if (proc != owner)
throw new ErlangError(ERT.am_badfun, args);

r.run();
return ERT.am_ok;
}
}, getClass().getClassLoader());
return EFun.get_fun_with_handler("java.lang.Runnable", "run", 0,
new EFunHandler() {
@Override
public EObject invoke(EProc proc, EObject[] args)
throws Pausable {
if (proc != owner)
throw new ErlangError(ERT.am_badfun, args);

r.run();
return ERT.am_ok;
}
}, getClass().getClassLoader());

}

Expand All @@ -151,22 +152,23 @@ public EObject invoke(EProc proc, EObject[] args)
*/
if ((nargs == 1) && (real_object instanceof java.util.Map<?, ?>)) {
final java.util.Map<?, ?> r = (java.util.Map<?, ?>) real_object;
return EFun.get_fun_with_handler(0, new EFunHandler() {
@Override
public EObject invoke(EProc self, EObject[] args)
throws Pausable {
if (self != owner)
throw new ErlangError(ERT.am_badfun, args);

Object key = JavaObject.unbox(self, Object.class, args[0]);
if (r.containsKey(key)) {
return new ETuple2(args[0], JavaObject.box(self, r
.get(key)));
} else {
return am_none;
return EFun.get_fun_with_handler("java.util.Map", "get", 0,
new EFunHandler() {
@Override
public EObject invoke(EProc self, EObject[] args)
throws Pausable {
if (self != owner)
throw new ErlangError(ERT.am_badfun, args);

Object key = JavaObject.unbox(self, Object.class, args[0]);
if (r.containsKey(key)) {
return new ETuple2(args[0], JavaObject.box(self, r
.get(key)));
} else {
return am_none;
}
}
}
}, getClass().getClassLoader());
}, getClass().getClassLoader());

}

Expand Down Expand Up @@ -428,7 +430,7 @@ public Object invoke(Object proxy, final Method method, final Object[] args)

final Mailbox<Object> reply = new Mailbox<Object>(1);

EFun job = EFun.get_fun_with_handler(0, new EFunHandler() {
EFun job = EFun.get_fun_with_handler("erlang", "apply", 0, new EFunHandler() {
@Override
public EObject invoke(EProc proc, EObject[] _) throws Pausable {

Expand Down Expand Up @@ -612,7 +614,7 @@ public EFun resolve_fun(final EAtom f, final int arity) {

// TODO: we can make this much much faster!

return EFun.get_fun_with_handler(arity,
return EFun.get_fun_with_handler("java.lang.Object", f.toString(), arity,

new EFunHandler() {
@Override
Expand Down

0 comments on commit e0a132b

Please sign in to comment.