Package org.fotap.heysync

Source Code of org.fotap.heysync.CallbackCreator

package org.fotap.heysync;

import org.jetlang.core.Callback;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import static org.fotap.heysync.AsmHelper.*;
import static org.objectweb.asm.Opcodes.*;

/**
* @author <a href="mailto:peter.royal@pobox.com">peter royal</a>
*/
class CallbackCreator extends ClassCreator<Callback> {
    private final Method method;
    private final Type receiverType;

    private static final Map<Type, Type> primitivesToBoxedTypes = new HashMap<Type, Type>();

    static {
        primitivesToBoxedTypes.put(Type.BOOLEAN_TYPE, Type.getType(Boolean.class));
        primitivesToBoxedTypes.put(Type.BYTE_TYPE, Type.getType(Byte.class));
        primitivesToBoxedTypes.put(Type.CHAR_TYPE, Type.getType(Character.class));
        primitivesToBoxedTypes.put(Type.DOUBLE_TYPE, Type.getType(Double.class));
        primitivesToBoxedTypes.put(Type.FLOAT_TYPE, Type.getType(Float.class));
        primitivesToBoxedTypes.put(Type.INT_TYPE, Type.getType(Integer.class));
        primitivesToBoxedTypes.put(Type.LONG_TYPE, Type.getType(Long.class));
        primitivesToBoxedTypes.put(Type.SHORT_TYPE, Type.getType(Short.class));
    }

    public CallbackCreator(Type outputType, Method method) {
        super(Callback.class, outputType);
        this.method = method;
        this.receiverType = Type.getType(method.getDeclaringClass());
    }

    @Override
    protected void createFields() {
        writer.visitField(ACC_PRIVATE + ACC_FINAL,
                "receiver",
                receiverType.getDescriptor(),
                null,
                null).visitEnd();
    }

    @Override
    protected void createConstructor() {
        String declaration = "void <init> (" + method.getDeclaringClass().getName() + ")";
        GeneratorAdapter adapter = method(ACC_PUBLIC, asmMethod(declaration));
        adapter.loadThis();
        adapter.invokeConstructor(objectType, defaultConstructor);
        adapter.loadThis();
        adapter.loadArg(0);
        adapter.putField(outputType(), "receiver", receiverType);
        adapter.returnValue();
        adapter.endMethod();
    }

    @Override
    protected void implementMethods() {
        Type callbackType = getCallbackType();
        org.objectweb.asm.commons.Method stronglyTypedMethod =
                asmMethod("void onMessage (" + callbackType.getClassName() + ")");

        stronglyTyped(stronglyTypedMethod, method.getParameterTypes());
        if (!callbackType.equals(objectType)) {
            synthetic(stronglyTypedMethod, callbackType);
        }
        meaningfulToString();
    }

    private Type getCallbackType() {
        if (method.getParameterTypes().length == 0) {
            return objectType;
        } else if (method.getParameterTypes().length == 1) {
            Type paramType = Type.getType(method.getParameterTypes()[0]);
            Type boxed = primitivesToBoxedTypes.get(paramType);
            return boxed != null ? boxed : paramType;
        } else {
            return Type.getType(Object[].class);
        }
    }

    private void meaningfulToString() {
        GeneratorAdapter adapter = method(ACC_PUBLIC, toString);
        adapter.newInstance(stringBuilder);
        adapter.dup();
        adapter.invokeConstructor(stringBuilder, stringBuilderConstructor);
        adapter.push("[" + methodName() + " on ");
        adapter.invokeVirtual(stringBuilder, appendString);
        loadReceiver(adapter);
        adapter.invokeVirtual(stringBuilder, appendObject);
        adapter.push("]");
        adapter.invokeVirtual(stringBuilder, appendString);
        adapter.invokeVirtual(objectType, toString);
        adapter.returnValue();
        adapter.endMethod();
    }

    private String methodName() {
        String[] strings = method.toGenericString().split(" ");
        return strings[strings.length - 1];
    }

    private void synthetic(org.objectweb.asm.commons.Method stronglyTypedMethod, Type callbackType) {
        GeneratorAdapter adapter = method(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC,
                asmMethod("void onMessage (" + Object.class.getName() + ")"));
        adapter.loadThis();
        adapter.loadArg(0);
        adapter.checkCast(callbackType);
        adapter.invokeVirtual(outputType(), stronglyTypedMethod);
        adapter.returnValue();
        adapter.endMethod();
    }

    private void stronglyTyped(org.objectweb.asm.commons.Method method, Class<?>[] paramTypes) {
        GeneratorAdapter adapter = method(ACC_PUBLIC, method);
        loadReceiver(adapter);
        loadArguments(adapter, paramTypes);
        adapter.invokeInterface(receiverType, asmMethod(this.method));
        adapter.returnValue();
        adapter.endMethod();
    }

    private void loadReceiver(GeneratorAdapter adapter) {
        adapter.loadThis();
        adapter.getField(outputType(), "receiver", receiverType);
    }

    private void loadArguments(GeneratorAdapter adapter, Class<?>[] paramTypes) {
        if (paramTypes.length == 1) {
            adapter.loadArg(0);
            Type type = Type.getType(paramTypes[0]);
            if (primitivesToBoxedTypes.containsKey(type)) {
                adapter.unbox(type);
            }
        } else if (paramTypes.length > 1) {
            for (int i = 0; i < paramTypes.length; i++) {
                adapter.loadArg(0);
                adapter.push(i);
                adapter.arrayLoad(objectType);
                Type type = Type.getType(paramTypes[i]);
                Type boxed = primitivesToBoxedTypes.get(type);
                if (boxed != null) {
                    adapter.checkCast(boxed);
                    adapter.unbox(type);
                } else {
                    adapter.checkCast(type);
                }
            }
        } // else paramTypes.length == 0: nothing to do
    }
}
TOP

Related Classes of org.fotap.heysync.CallbackCreator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.