Search in sources :

Example 26 with GeneratorAdapter

use of org.objectweb.asm.commons.GeneratorAdapter in project lucene-solr by apache.

the class JavascriptCompiler method generateClass.

/**
   * Sends the bytecode of class file to {@link ClassWriter}.
   */
private void generateClass(final ParseTree parseTree, final ClassWriter classWriter, final Map<String, Integer> externalsMap) throws ParseException {
    classWriter.visit(CLASSFILE_VERSION, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER | Opcodes.ACC_FINAL, COMPILED_EXPRESSION_INTERNAL, null, EXPRESSION_TYPE.getInternalName(), null);
    final String clippedSourceText = (sourceText.length() <= MAX_SOURCE_LENGTH) ? sourceText : (sourceText.substring(0, MAX_SOURCE_LENGTH - 3) + "...");
    classWriter.visitSource(clippedSourceText, null);
    final GeneratorAdapter constructor = new GeneratorAdapter(Opcodes.ACC_PUBLIC, EXPRESSION_CTOR, null, null, classWriter);
    constructor.loadThis();
    constructor.loadArgs();
    constructor.invokeConstructor(EXPRESSION_TYPE, EXPRESSION_CTOR);
    constructor.returnValue();
    constructor.endMethod();
    final GeneratorAdapter gen = new GeneratorAdapter(Opcodes.ACC_PUBLIC, EVALUATE_METHOD, null, null, classWriter);
    // to completely hide the ANTLR visitor we use an anonymous impl:
    new JavascriptBaseVisitor<Void>() {

        private final Deque<Type> typeStack = new ArrayDeque<>();

        @Override
        public Void visitCompile(JavascriptParser.CompileContext ctx) {
            typeStack.push(Type.DOUBLE_TYPE);
            visit(ctx.expression());
            typeStack.pop();
            return null;
        }

        @Override
        public Void visitPrecedence(JavascriptParser.PrecedenceContext ctx) {
            visit(ctx.expression());
            return null;
        }

        @Override
        public Void visitNumeric(JavascriptParser.NumericContext ctx) {
            if (ctx.HEX() != null) {
                pushLong(Long.parseLong(ctx.HEX().getText().substring(2), 16));
            } else if (ctx.OCTAL() != null) {
                pushLong(Long.parseLong(ctx.OCTAL().getText().substring(1), 8));
            } else if (ctx.DECIMAL() != null) {
                gen.push(Double.parseDouble(ctx.DECIMAL().getText()));
                gen.cast(Type.DOUBLE_TYPE, typeStack.peek());
            } else {
                throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
            }
            return null;
        }

        @Override
        public Void visitExternal(JavascriptParser.ExternalContext ctx) {
            String text = ctx.VARIABLE().getText();
            int arguments = ctx.expression().size();
            boolean parens = ctx.LP() != null && ctx.RP() != null;
            Method method = parens ? functions.get(text) : null;
            try {
                if (method != null) {
                    int arity = method.getParameterTypes().length;
                    if (arguments != arity) {
                        throw new ParseException("Invalid expression '" + sourceText + "': Expected (" + arity + ") arguments for function call (" + text + "), but found (" + arguments + ").", ctx.start.getStartIndex());
                    }
                    typeStack.push(Type.DOUBLE_TYPE);
                    for (int argument = 0; argument < arguments; ++argument) {
                        visit(ctx.expression(argument));
                    }
                    typeStack.pop();
                    gen.invokeStatic(Type.getType(method.getDeclaringClass()), org.objectweb.asm.commons.Method.getMethod(method));
                    gen.cast(Type.DOUBLE_TYPE, typeStack.peek());
                } else if (!parens || arguments == 0 && text.contains(".")) {
                    int index;
                    text = normalizeQuotes(ctx.getText());
                    if (externalsMap.containsKey(text)) {
                        index = externalsMap.get(text);
                    } else {
                        index = externalsMap.size();
                        externalsMap.put(text, index);
                    }
                    gen.loadArg(0);
                    gen.push(index);
                    gen.arrayLoad(FUNCTION_VALUES_TYPE);
                    gen.invokeVirtual(FUNCTION_VALUES_TYPE, DOUBLE_VAL_METHOD);
                    gen.cast(Type.DOUBLE_TYPE, typeStack.peek());
                } else {
                    throw new ParseException("Invalid expression '" + sourceText + "': Unrecognized function call (" + text + ").", ctx.start.getStartIndex());
                }
                return null;
            } catch (ParseException e) {
                // in getAntlrParseTree. 
                throw new RuntimeException(e);
            }
        }

        @Override
        public Void visitUnary(JavascriptParser.UnaryContext ctx) {
            if (ctx.BOOLNOT() != null) {
                Label labelNotTrue = new Label();
                Label labelNotReturn = new Label();
                typeStack.push(Type.INT_TYPE);
                visit(ctx.expression());
                typeStack.pop();
                gen.visitJumpInsn(Opcodes.IFEQ, labelNotTrue);
                pushBoolean(false);
                gen.goTo(labelNotReturn);
                gen.visitLabel(labelNotTrue);
                pushBoolean(true);
                gen.visitLabel(labelNotReturn);
            } else if (ctx.BWNOT() != null) {
                typeStack.push(Type.LONG_TYPE);
                visit(ctx.expression());
                typeStack.pop();
                gen.push(-1L);
                gen.visitInsn(Opcodes.LXOR);
                gen.cast(Type.LONG_TYPE, typeStack.peek());
            } else if (ctx.ADD() != null) {
                visit(ctx.expression());
            } else if (ctx.SUB() != null) {
                typeStack.push(Type.DOUBLE_TYPE);
                visit(ctx.expression());
                typeStack.pop();
                gen.visitInsn(Opcodes.DNEG);
                gen.cast(Type.DOUBLE_TYPE, typeStack.peek());
            } else {
                throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
            }
            return null;
        }

        @Override
        public Void visitMuldiv(JavascriptParser.MuldivContext ctx) {
            int opcode;
            if (ctx.MUL() != null) {
                opcode = Opcodes.DMUL;
            } else if (ctx.DIV() != null) {
                opcode = Opcodes.DDIV;
            } else if (ctx.REM() != null) {
                opcode = Opcodes.DREM;
            } else {
                throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
            }
            pushArith(opcode, ctx.expression(0), ctx.expression(1));
            return null;
        }

        @Override
        public Void visitAddsub(JavascriptParser.AddsubContext ctx) {
            int opcode;
            if (ctx.ADD() != null) {
                opcode = Opcodes.DADD;
            } else if (ctx.SUB() != null) {
                opcode = Opcodes.DSUB;
            } else {
                throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
            }
            pushArith(opcode, ctx.expression(0), ctx.expression(1));
            return null;
        }

        @Override
        public Void visitBwshift(JavascriptParser.BwshiftContext ctx) {
            int opcode;
            if (ctx.LSH() != null) {
                opcode = Opcodes.LSHL;
            } else if (ctx.RSH() != null) {
                opcode = Opcodes.LSHR;
            } else if (ctx.USH() != null) {
                opcode = Opcodes.LUSHR;
            } else {
                throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
            }
            pushShift(opcode, ctx.expression(0), ctx.expression(1));
            return null;
        }

        @Override
        public Void visitBoolcomp(JavascriptParser.BoolcompContext ctx) {
            int opcode;
            if (ctx.LT() != null) {
                opcode = GeneratorAdapter.LT;
            } else if (ctx.LTE() != null) {
                opcode = GeneratorAdapter.LE;
            } else if (ctx.GT() != null) {
                opcode = GeneratorAdapter.GT;
            } else if (ctx.GTE() != null) {
                opcode = GeneratorAdapter.GE;
            } else {
                throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
            }
            pushCond(opcode, ctx.expression(0), ctx.expression(1));
            return null;
        }

        @Override
        public Void visitBooleqne(JavascriptParser.BooleqneContext ctx) {
            int opcode;
            if (ctx.EQ() != null) {
                opcode = GeneratorAdapter.EQ;
            } else if (ctx.NE() != null) {
                opcode = GeneratorAdapter.NE;
            } else {
                throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
            }
            pushCond(opcode, ctx.expression(0), ctx.expression(1));
            return null;
        }

        @Override
        public Void visitBwand(JavascriptParser.BwandContext ctx) {
            pushBitwise(Opcodes.LAND, ctx.expression(0), ctx.expression(1));
            return null;
        }

        @Override
        public Void visitBwxor(JavascriptParser.BwxorContext ctx) {
            pushBitwise(Opcodes.LXOR, ctx.expression(0), ctx.expression(1));
            return null;
        }

        @Override
        public Void visitBwor(JavascriptParser.BworContext ctx) {
            pushBitwise(Opcodes.LOR, ctx.expression(0), ctx.expression(1));
            return null;
        }

        @Override
        public Void visitBooland(JavascriptParser.BoolandContext ctx) {
            Label andFalse = new Label();
            Label andEnd = new Label();
            typeStack.push(Type.INT_TYPE);
            visit(ctx.expression(0));
            gen.visitJumpInsn(Opcodes.IFEQ, andFalse);
            visit(ctx.expression(1));
            gen.visitJumpInsn(Opcodes.IFEQ, andFalse);
            typeStack.pop();
            pushBoolean(true);
            gen.goTo(andEnd);
            gen.visitLabel(andFalse);
            pushBoolean(false);
            gen.visitLabel(andEnd);
            return null;
        }

        @Override
        public Void visitBoolor(JavascriptParser.BoolorContext ctx) {
            Label orTrue = new Label();
            Label orEnd = new Label();
            typeStack.push(Type.INT_TYPE);
            visit(ctx.expression(0));
            gen.visitJumpInsn(Opcodes.IFNE, orTrue);
            visit(ctx.expression(1));
            gen.visitJumpInsn(Opcodes.IFNE, orTrue);
            typeStack.pop();
            pushBoolean(false);
            gen.goTo(orEnd);
            gen.visitLabel(orTrue);
            pushBoolean(true);
            gen.visitLabel(orEnd);
            return null;
        }

        @Override
        public Void visitConditional(JavascriptParser.ConditionalContext ctx) {
            Label condFalse = new Label();
            Label condEnd = new Label();
            typeStack.push(Type.INT_TYPE);
            visit(ctx.expression(0));
            typeStack.pop();
            gen.visitJumpInsn(Opcodes.IFEQ, condFalse);
            visit(ctx.expression(1));
            gen.goTo(condEnd);
            gen.visitLabel(condFalse);
            visit(ctx.expression(2));
            gen.visitLabel(condEnd);
            return null;
        }

        private void pushArith(int operator, ExpressionContext left, ExpressionContext right) {
            pushBinaryOp(operator, left, right, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE);
        }

        private void pushShift(int operator, ExpressionContext left, ExpressionContext right) {
            pushBinaryOp(operator, left, right, Type.LONG_TYPE, Type.INT_TYPE, Type.LONG_TYPE);
        }

        private void pushBitwise(int operator, ExpressionContext left, ExpressionContext right) {
            pushBinaryOp(operator, left, right, Type.LONG_TYPE, Type.LONG_TYPE, Type.LONG_TYPE);
        }

        private void pushBinaryOp(int operator, ExpressionContext left, ExpressionContext right, Type leftType, Type rightType, Type returnType) {
            typeStack.push(leftType);
            visit(left);
            typeStack.pop();
            typeStack.push(rightType);
            visit(right);
            typeStack.pop();
            gen.visitInsn(operator);
            gen.cast(returnType, typeStack.peek());
        }

        private void pushCond(int operator, ExpressionContext left, ExpressionContext right) {
            Label labelTrue = new Label();
            Label labelReturn = new Label();
            typeStack.push(Type.DOUBLE_TYPE);
            visit(left);
            visit(right);
            typeStack.pop();
            gen.ifCmp(Type.DOUBLE_TYPE, operator, labelTrue);
            pushBoolean(false);
            gen.goTo(labelReturn);
            gen.visitLabel(labelTrue);
            pushBoolean(true);
            gen.visitLabel(labelReturn);
        }

        private void pushBoolean(boolean truth) {
            switch(typeStack.peek().getSort()) {
                case Type.INT:
                    gen.push(truth);
                    break;
                case Type.LONG:
                    gen.push(truth ? 1L : 0L);
                    break;
                case Type.DOUBLE:
                    gen.push(truth ? 1. : 0.);
                    break;
                default:
                    throw new IllegalStateException("Invalid expected type: " + typeStack.peek());
            }
        }

        private void pushLong(long i) {
            switch(typeStack.peek().getSort()) {
                case Type.INT:
                    gen.push((int) i);
                    break;
                case Type.LONG:
                    gen.push(i);
                    break;
                case Type.DOUBLE:
                    gen.push((double) i);
                    break;
                default:
                    throw new IllegalStateException("Invalid expected type: " + typeStack.peek());
            }
        }
    }.visit(parseTree);
    gen.returnValue();
    gen.endMethod();
    classWriter.visitEnd();
}
Also used : Label(org.objectweb.asm.Label) Method(java.lang.reflect.Method) ArrayDeque(java.util.ArrayDeque) Type(org.objectweb.asm.Type) MethodType(java.lang.invoke.MethodType) ExpressionContext(org.apache.lucene.expressions.js.JavascriptParser.ExpressionContext) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) ParseException(java.text.ParseException)

Example 27 with GeneratorAdapter

use of org.objectweb.asm.commons.GeneratorAdapter in project cdap by caskdata.

the class Classes method rewriteMethodToNoop.

/**
   * Rewrites methods in the given class bytecode to noop methods.
   */
public static byte[] rewriteMethodToNoop(final String className, InputStream byteCodeStream, final Set<String> methods) throws IOException {
    ClassReader cr = new ClassReader(byteCodeStream);
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {

        @Override
        public MethodVisitor visitMethod(final int access, final String name, final String desc, String signature, String[] exceptions) {
            MethodVisitor methodVisitor = super.visitMethod(access, name, desc, signature, exceptions);
            if (!methods.contains(name)) {
                return methodVisitor;
            }
            // We can only rewrite method that returns void
            if (!Type.getReturnType(desc).equals(Type.VOID_TYPE)) {
                LOG.warn("Cannot patch method {} in {} due to non-void return type: {}", name, className, desc);
                return methodVisitor;
            }
            // Rewrite the method to noop.
            GeneratorAdapter adapter = new GeneratorAdapter(methodVisitor, access, name, desc);
            adapter.returnValue();
            // VisitMaxs with 0 so that COMPUTE_MAXS from ClassWriter will compute the right values.
            adapter.visitMaxs(0, 0);
            return new MethodVisitor(Opcodes.ASM5) {
            };
        }
    }, 0);
    return cw.toByteArray();
}
Also used : ClassReader(org.objectweb.asm.ClassReader) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) ClassVisitor(org.objectweb.asm.ClassVisitor) ClassWriter(org.objectweb.asm.ClassWriter) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 28 with GeneratorAdapter

use of org.objectweb.asm.commons.GeneratorAdapter in project cdap by caskdata.

the class FieldAccessorGenerator method invokeReflection.

/**
   * Generates the try-catch block that wrap around the given reflection method call.
   * @param method The method to be called within the try-catch block.
   */
private void invokeReflection(Method method, String signature) {
    GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, method, signature, new Type[0], classWriter);
    /**
     * try {
     *   // Call method
     * } catch (IllegalAccessException e) {
     *   throw Throwables.propagate(e);
     * }
     */
    Label beginTry = mg.newLabel();
    Label endTry = mg.newLabel();
    Label catchHandle = mg.newLabel();
    mg.visitTryCatchBlock(beginTry, endTry, catchHandle, Type.getInternalName(IllegalAccessException.class));
    mg.mark(beginTry);
    mg.loadThis();
    mg.getField(Type.getObjectType(className), "field", Type.getType(Field.class));
    mg.loadArgs();
    mg.invokeVirtual(Type.getType(Field.class), method);
    mg.mark(endTry);
    mg.returnValue();
    mg.mark(catchHandle);
    int exception = mg.newLocal(Type.getType(IllegalAccessException.class));
    mg.storeLocal(exception);
    mg.loadLocal(exception);
    mg.invokeStatic(Type.getType(Throwables.class), getMethod(RuntimeException.class, "propagate", Throwable.class));
    mg.throwException();
    mg.endMethod();
}
Also used : Field(java.lang.reflect.Field) Throwables(com.google.common.base.Throwables) Label(org.objectweb.asm.Label) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter)

Example 29 with GeneratorAdapter

use of org.objectweb.asm.commons.GeneratorAdapter in project cdap by caskdata.

the class FieldAccessorGenerator method directSetter.

/**
   * Generates a setter that set the value by directly accessing the class field.
   * @param field The reflection field object.
   */
private void directSetter(Field field) {
    GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, getMethod(void.class, "set", Object.class, Object.class), setterSignature(), new Type[0], classWriter);
    // Simply access by field
    // ((classType)object).fieldName = (valueType)value;
    mg.loadArg(0);
    mg.checkCast(Type.getType(field.getDeclaringClass()));
    mg.loadArg(1);
    if (field.getType().isPrimitive()) {
        mg.unbox(Type.getType(field.getType()));
    } else {
        mg.checkCast(Type.getType(field.getType()));
    }
    mg.putField(Type.getType(field.getDeclaringClass()), field.getName(), Type.getType(field.getType()));
    mg.returnValue();
    mg.endMethod();
}
Also used : GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter)

Example 30 with GeneratorAdapter

use of org.objectweb.asm.commons.GeneratorAdapter in project cdap by caskdata.

the class HttpHandlerGenerator method generateConstructor.

/**
   * Generates the constructor. The constructor generated has signature {@code (DelegatorContext, MetricsContext)}.
   */
private void generateConstructor(TypeToken<? extends HttpServiceHandler> delegateType, ClassWriter classWriter) {
    Method constructor = Methods.getMethod(void.class, "<init>", DelegatorContext.class, MetricsContext.class);
    String signature = Signatures.getMethodSignature(constructor, TypeToken.of(void.class), getContextType(delegateType), TypeToken.of(MetricsContext.class));
    // Constructor(DelegatorContext, MetricsContext)
    GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, constructor, signature, null, classWriter);
    // super(context, metricsContext);
    mg.loadThis();
    mg.loadArg(0);
    mg.loadArg(1);
    mg.invokeConstructor(Type.getType(AbstractHttpHandlerDelegator.class), Methods.getMethod(void.class, "<init>", DelegatorContext.class, MetricsContext.class));
    mg.returnValue();
    mg.endMethod();
}
Also used : MetricsContext(co.cask.cdap.api.metrics.MetricsContext) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) Method(org.objectweb.asm.commons.Method)

Aggregations

GeneratorAdapter (org.objectweb.asm.commons.GeneratorAdapter)33 Method (org.objectweb.asm.commons.Method)24 Type (org.objectweb.asm.Type)14 Label (org.objectweb.asm.Label)8 ClassWriter (org.objectweb.asm.ClassWriter)7 MethodVisitor (org.objectweb.asm.MethodVisitor)7 IOException (java.io.IOException)5 ClassReader (org.objectweb.asm.ClassReader)5 ClassVisitor (org.objectweb.asm.ClassVisitor)4 Schema (co.cask.cdap.api.data.schema.Schema)3 TypeToken (com.google.common.reflect.TypeToken)2 InvocationHandler (java.lang.reflect.InvocationHandler)2 ArrayList (java.util.ArrayList)2 Set (java.util.Set)2 SchemaHash (co.cask.cdap.api.data.schema.SchemaHash)1 MetricsContext (co.cask.cdap.api.metrics.MetricsContext)1 Encoder (co.cask.cdap.common.io.Encoder)1 Throwables (com.google.common.base.Throwables)1 Sets (com.google.common.collect.Sets)1 File (java.io.File)1