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();
}
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();
}
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();
}
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();
}
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();
}
Aggregations