com.facebook.presto.bytecode.instruction.InvokeInstruction.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.presto.bytecode.instruction.InvokeInstruction.java

Source

/*
 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.facebook.presto.bytecode.instruction;

import com.facebook.presto.bytecode.BytecodeNode;
import com.facebook.presto.bytecode.BytecodeVisitor;
import com.facebook.presto.bytecode.MethodDefinition;
import com.facebook.presto.bytecode.MethodGenerationContext;
import com.facebook.presto.bytecode.OpCode;
import com.facebook.presto.bytecode.ParameterizedType;
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableList;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;

import static com.facebook.presto.bytecode.MethodDefinition.methodDescription;
import static com.facebook.presto.bytecode.OpCode.INVOKEDYNAMIC;
import static com.facebook.presto.bytecode.OpCode.INVOKEINTERFACE;
import static com.facebook.presto.bytecode.OpCode.INVOKESPECIAL;
import static com.facebook.presto.bytecode.OpCode.INVOKESTATIC;
import static com.facebook.presto.bytecode.OpCode.INVOKEVIRTUAL;
import static com.facebook.presto.bytecode.ParameterizedType.type;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.transform;
import static java.util.Objects.requireNonNull;

@SuppressWarnings("UnusedDeclaration")
public class InvokeInstruction implements InstructionNode {
    //
    // Invoke Static
    //

    public static InstructionNode invokeStatic(Method method) {
        return invoke(INVOKESTATIC, method);
    }

    public static InstructionNode invokeStatic(MethodDefinition method) {
        return invoke(INVOKESTATIC, method);
    }

    public static InstructionNode invokeStatic(Class<?> target, String name, Class<?> returnType,
            Class<?>... parameterTypes) {
        return invoke(INVOKESTATIC, target, name, returnType, ImmutableList.copyOf(parameterTypes));
    }

    public static InstructionNode invokeStatic(Class<?> target, String name, Class<?> returnType,
            Iterable<Class<?>> parameterTypes) {
        return invoke(INVOKESTATIC, target, name, returnType, parameterTypes);
    }

    public static InstructionNode invokeStatic(ParameterizedType target, String name, ParameterizedType returnType,
            ParameterizedType... parameterTypes) {
        return invoke(INVOKESTATIC, target, name, returnType, ImmutableList.copyOf(parameterTypes));
    }

    public static InstructionNode invokeStatic(ParameterizedType target, String name, ParameterizedType returnType,
            Iterable<ParameterizedType> parameterTypes) {
        return invoke(INVOKESTATIC, target, name, returnType, parameterTypes);
    }

    //
    // Invoke Virtual
    //

    public static InstructionNode invokeVirtual(Method method) {
        return invoke(INVOKEVIRTUAL, method);
    }

    public static InstructionNode invokeVirtual(MethodDefinition method) {
        return invoke(INVOKEVIRTUAL, method);
    }

    public static InstructionNode invokeVirtual(Class<?> target, String name, Class<?> returnType,
            Class<?>... parameterTypes) {
        return invoke(INVOKEVIRTUAL, target, name, returnType, ImmutableList.copyOf(parameterTypes));
    }

    public static InstructionNode invokeVirtual(Class<?> target, String name, Class<?> returnType,
            Iterable<Class<?>> parameterTypes) {
        return invoke(INVOKEVIRTUAL, target, name, returnType, parameterTypes);
    }

    public static InstructionNode invokeVirtual(ParameterizedType target, String name, ParameterizedType returnType,
            ParameterizedType... parameterTypes) {
        return invoke(INVOKEVIRTUAL, target, name, returnType, ImmutableList.copyOf(parameterTypes));
    }

    public static InstructionNode invokeVirtual(ParameterizedType target, String name, ParameterizedType returnType,
            Iterable<ParameterizedType> parameterTypes) {
        return invoke(INVOKEVIRTUAL, target, name, returnType, parameterTypes);
    }

    //
    // Invoke Interface
    //

    public static InstructionNode invokeInterface(Method method) {
        return invoke(INVOKEINTERFACE, method);
    }

    public static InstructionNode invokeInterface(MethodDefinition method) {
        return invoke(INVOKEINTERFACE, method);
    }

    public static InstructionNode invokeInterface(Class<?> target, String name, Class<?> returnType,
            Class<?>... parameterTypes) {
        return invoke(INVOKEINTERFACE, target, name, returnType, ImmutableList.copyOf(parameterTypes));
    }

    public static InstructionNode invokeInterface(Class<?> target, String name, Class<?> returnType,
            Iterable<Class<?>> parameterTypes) {
        return invoke(INVOKEINTERFACE, target, name, returnType, parameterTypes);
    }

    public static InstructionNode invokeInterface(ParameterizedType target, String name,
            ParameterizedType returnType, ParameterizedType... parameterTypes) {
        return invoke(INVOKEINTERFACE, target, name, returnType, ImmutableList.copyOf(parameterTypes));
    }

    public static InstructionNode invokeInterface(ParameterizedType target, String name,
            ParameterizedType returnType, Iterable<ParameterizedType> parameterTypes) {
        return invoke(INVOKEINTERFACE, target, name, returnType, parameterTypes);
    }

    //
    // Invoke Constructor
    //

    public static InstructionNode invokeConstructor(Constructor<?> constructor) {
        return invokeConstructor(constructor.getDeclaringClass(), constructor.getParameterTypes());
    }

    public static InstructionNode invokeConstructor(Class<?> target, Class<?>... parameterTypes) {
        return invokeConstructor(type(target),
                transform(ImmutableList.copyOf(parameterTypes), ParameterizedType::type));
    }

    public static InstructionNode invokeConstructor(Class<?> target, Iterable<Class<?>> parameterTypes) {
        return invokeConstructor(type(target), transform(parameterTypes, ParameterizedType::type));
    }

    public static InstructionNode invokeConstructor(ParameterizedType target, ParameterizedType... parameterTypes) {
        return invokeConstructor(target, ImmutableList.copyOf(parameterTypes));
    }

    public static InstructionNode invokeConstructor(ParameterizedType target,
            Iterable<ParameterizedType> parameterTypes) {
        return invokeSpecial(target, "<init>", type(void.class), parameterTypes);
    }

    //
    // Invoke Special
    //

    public static InstructionNode invokeSpecial(Method method) {
        return invoke(INVOKESPECIAL, method);
    }

    public static InstructionNode invokeSpecial(MethodDefinition method) {
        return invoke(INVOKESPECIAL, method);
    }

    public static InstructionNode invokeSpecial(Class<?> target, String name, Class<?> returnType,
            Class<?>... parameterTypes) {
        return invoke(INVOKESPECIAL, target, name, returnType, ImmutableList.copyOf(parameterTypes));
    }

    public static InstructionNode invokeSpecial(Class<?> target, String name, Class<?> returnType,
            Iterable<Class<?>> parameterTypes) {
        return invoke(INVOKESPECIAL, target, name, returnType, parameterTypes);
    }

    public static InstructionNode invokeSpecial(ParameterizedType target, String name, ParameterizedType returnType,
            ParameterizedType... parameterTypes) {
        return invoke(INVOKESPECIAL, target, name, returnType, ImmutableList.copyOf(parameterTypes));
    }

    public static InstructionNode invokeSpecial(ParameterizedType target, String name, ParameterizedType returnType,
            Iterable<ParameterizedType> parameterTypes) {
        return invoke(INVOKESPECIAL, target, name, returnType, parameterTypes);
    }

    //
    // Generic
    //

    private static InstructionNode invoke(OpCode invocationType, Method method) {
        return new InvokeInstruction(invocationType, type(method.getDeclaringClass()), method.getName(),
                type(method.getReturnType()),
                transform(ImmutableList.copyOf(method.getParameterTypes()), ParameterizedType::type));
    }

    private static InstructionNode invoke(OpCode invocationType, MethodDefinition method) {
        return new InvokeInstruction(invocationType, method.getDeclaringClass().getType(), method.getName(),
                method.getReturnType(), method.getParameterTypes());
    }

    private static InstructionNode invoke(OpCode invocationType, ParameterizedType target, String name,
            ParameterizedType returnType, Iterable<ParameterizedType> parameterTypes) {
        return new InvokeInstruction(invocationType, target, name, returnType, parameterTypes);
    }

    private static InstructionNode invoke(OpCode invocationType, Class<?> target, String name, Class<?> returnType,
            Iterable<Class<?>> parameterTypes) {
        return new InvokeInstruction(invocationType, type(target), name, type(returnType),
                transform(parameterTypes, ParameterizedType::type));
    }

    //
    // Invoke Dynamic
    //

    public static InstructionNode invokeDynamic(String name, ParameterizedType returnType,
            Iterable<ParameterizedType> parameterTypes, Method bootstrapMethod,
            Iterable<Object> bootstrapArguments) {
        return new InvokeDynamicInstruction(name, returnType, parameterTypes, bootstrapMethod,
                ImmutableList.copyOf(bootstrapArguments));
    }

    public static InstructionNode invokeDynamic(String name, ParameterizedType returnType,
            Iterable<ParameterizedType> parameterTypes, Method bootstrapMethod, Object... bootstrapArguments) {
        return new InvokeDynamicInstruction(name, returnType, parameterTypes, bootstrapMethod,
                ImmutableList.copyOf(bootstrapArguments));
    }

    public static InstructionNode invokeDynamic(String name, MethodType methodType, Method bootstrapMethod,
            Iterable<Object> bootstrapArguments) {
        return new InvokeDynamicInstruction(name, type(methodType.returnType()),
                transform(methodType.parameterList(), ParameterizedType::type), bootstrapMethod,
                ImmutableList.copyOf(bootstrapArguments));
    }

    public static InstructionNode invokeDynamic(String name, MethodType methodType, Method bootstrapMethod,
            Object... bootstrapArguments) {
        return new InvokeDynamicInstruction(name, type(methodType.returnType()),
                transform(methodType.parameterList(), ParameterizedType::type), bootstrapMethod,
                ImmutableList.copyOf(bootstrapArguments));
    }

    private final OpCode opCode;
    private final ParameterizedType target;
    private final String name;
    private final ParameterizedType returnType;
    private final List<ParameterizedType> parameterTypes;

    public InvokeInstruction(OpCode opCode, ParameterizedType target, String name, ParameterizedType returnType,
            Iterable<ParameterizedType> parameterTypes) {
        checkUnqualifiedName(name);
        this.opCode = opCode;
        this.target = target;
        this.name = name;
        this.returnType = returnType;
        this.parameterTypes = ImmutableList.copyOf(parameterTypes);
    }

    public OpCode getOpCode() {
        return opCode;
    }

    public ParameterizedType getTarget() {
        return target;
    }

    public String getName() {
        return name;
    }

    public ParameterizedType getReturnType() {
        return returnType;
    }

    public List<ParameterizedType> getParameterTypes() {
        return parameterTypes;
    }

    public String getMethodDescription() {
        return methodDescription(returnType, parameterTypes);
    }

    @Override
    public void accept(MethodVisitor visitor, MethodGenerationContext generationContext) {
        visitor.visitMethodInsn(opCode.getOpCode(), target.getClassName(), name, getMethodDescription());
    }

    @Override
    public List<BytecodeNode> getChildNodes() {
        return ImmutableList.of();
    }

    @Override
    public <T> T accept(BytecodeNode parent, BytecodeVisitor<T> visitor) {
        return visitor.visitInvoke(parent, this);
    }

    public static class InvokeDynamicInstruction extends InvokeInstruction {
        private final Method bootstrapMethod;
        private final List<Object> bootstrapArguments;

        public InvokeDynamicInstruction(String name, ParameterizedType returnType,
                Iterable<ParameterizedType> parameterTypes, Method bootstrapMethod,
                List<Object> bootstrapArguments) {
            super(INVOKEDYNAMIC, null, name, returnType, parameterTypes);
            this.bootstrapMethod = bootstrapMethod;
            this.bootstrapArguments = ImmutableList.copyOf(bootstrapArguments);
        }

        @Override
        public void accept(MethodVisitor visitor, MethodGenerationContext generationContext) {
            Handle bootstrapMethodHandle = new Handle(Opcodes.H_INVOKESTATIC,
                    type(bootstrapMethod.getDeclaringClass()).getClassName(), bootstrapMethod.getName(),
                    methodDescription(bootstrapMethod.getReturnType(), bootstrapMethod.getParameterTypes()));

            visitor.visitInvokeDynamicInsn(getName(), getMethodDescription(), bootstrapMethodHandle,
                    bootstrapArguments.toArray(new Object[bootstrapArguments.size()]));
        }

        public Method getBootstrapMethod() {
            return bootstrapMethod;
        }

        public List<Object> getBootstrapArguments() {
            return bootstrapArguments;
        }

        @Override
        public List<BytecodeNode> getChildNodes() {
            return ImmutableList.of();
        }

        @Override
        public <T> T accept(BytecodeNode parent, BytecodeVisitor<T> visitor) {
            return visitor.visitInvokeDynamic(parent, this);
        }
    }

    private static void checkUnqualifiedName(String name) {
        // JVM Specification 4.2.2 Unqualified Names
        requireNonNull(name, "name is null");
        checkArgument(!name.isEmpty(), "name is empty");
        if (name.equals("<init>") || name.equals("<clinit>")) {
            return;
        }
        CharMatcher invalid = CharMatcher.anyOf(".;[/<>");
        checkArgument(invalid.matchesNoneOf(name), "invalid name: %s", name);
    }
}