org.apache.drill.exec.compile.bytecode.AloadPopRemover Maven / Gradle / Ivy
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.drill.exec.compile.bytecode;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.TypePath;
/**
* Remove any adjacent ALOAD-POP instruction pairs.
*
* The Janino compiler generates an instruction stream where it will ALOAD a
* holder's objectref, and then immediately POP it because the compiler has
* recognized that the method call that it loaded the objectref for is static
* (i.e., no this pointer is required). This causes a problem with our scalar
* replacement strategy, because once we remove the holders, we simply eliminate
* the ALOAD instructions. In this case, the POP gets left behind, and breaks
* the program stack.
*
* This class looks for ALOADs that are immediately followed by a POP, and removes
* the pair of instructions altogether.
*
* It is unknown if other compilers besides Janino generate this instruction sequence,
* but to be on the safe side, we'll use this class unconditionally to filter bytecode.
*
* TODO: this might be easier to do by going off an InsnList; the state machine would
* be in the loop that visits the instructions then.
*/
public class AloadPopRemover extends MethodVisitor {
private final static int NONE = -1; // var value to indicate no captured ALOAD
private int var = NONE;
/**
* Constructor.
*
* See {@link org.objectweb.asm.MethodVisitor#MethodVisitor(int)}.
*/
public AloadPopRemover(final int api) {
super(api);
}
/**
* Constructor.
*
* See {@link org.objectweb.asm.MethodVisitor#MethodVisitor(int, MethodVisitor)}.
*/
public AloadPopRemover(final int api, final MethodVisitor mv) {
super(api, mv);
}
/**
* Process a deferred ALOAD instruction, if there is one.
*
* If there is no deferred ALOAD, does nothing, and returns false.
*
* If there is a deferred ALOAD, and we're on a POP instruction
* (indicated by onPop), does nothing (the ALOAD is not forwarded),
* and returns true.
*
* If there is a deferred ALOAD and we're not on a POP instruction,
* forwards the deferred ALOAD, and returns false
*
* @param onPop true if the current instruction is POP
* @return true if onPop and there was a deferred ALOAD, false otherwise;
* basically, returns true if the ALOAD-POP optimization is required
*/
private boolean processDeferredAload(final boolean onPop) {
// if the previous instruction wasn't an ALOAD, then there's nothing to do
if (var == NONE) {
return false;
}
// clear the variable index, but save it for local use
final int localVar = var;
var = NONE;
// if the next instruction is a POP, don't emit the deferred ALOAD
if (onPop) {
return true;
}
// if we got here, we're not on a POP, so emit the deferred ALOAD
super.visitVarInsn(Opcodes.ALOAD, localVar);
return false;
}
@Override
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
processDeferredAload(false);
final AnnotationVisitor annotationVisitor = super.visitAnnotation(desc, visible);
return annotationVisitor;
}
@Override
public AnnotationVisitor visitAnnotationDefault() {
processDeferredAload(false);
final AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();
return annotationVisitor;
}
@Override
public void visitAttribute(final Attribute attr) {
processDeferredAload(false);
super.visitAttribute(attr);
}
@Override
public void visitCode() {
processDeferredAload(false);
super.visitCode();
}
@Override
public void visitEnd() {
processDeferredAload(false);
super.visitEnd();
}
@Override
public void visitFieldInsn(final int opcode, final String owner, final String name,
final String desc) {
processDeferredAload(false);
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitFrame(final int type, final int nLocal,
final Object[] local, final int nStack, final Object[] stack) {
processDeferredAload(false);
super.visitFrame(type, nLocal, local, nStack, stack);
}
@Override
public void visitIincInsn(final int var, final int increment) {
processDeferredAload(false);
super.visitIincInsn(var, increment);
}
@Override
public void visitInsn(final int opcode) {
/*
* If we don't omit an ALOAD with a following POP, then forward this.
* In other words, if we omit an ALOAD because we're on the following POP,
* don't forward this POP, which omits the ALOAD-POP pair.
*/
if (!processDeferredAload(Opcodes.POP == opcode)) {
super.visitInsn(opcode);
}
}
@Override
public AnnotationVisitor visitInsnAnnotation(final int typeRef,
final TypePath typePath, final String desc, final boolean visible) {
processDeferredAload(false);
final AnnotationVisitor annotationVisitor = super.visitInsnAnnotation(
typeRef, typePath, desc, visible);
return annotationVisitor;
}
@Override
public void visitIntInsn(final int opcode, final int operand) {
processDeferredAload(false);
super.visitIntInsn(opcode, operand);
}
@Override
public void visitInvokeDynamicInsn(final String name, final String desc,
final Handle bsm, final Object... bsmArgs) {
processDeferredAload(false);
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
@Override
public void visitJumpInsn(final int opcode, final Label label) {
processDeferredAload(false);
super.visitJumpInsn(opcode, label);
}
@Override
public void visitLabel(final Label label) {
processDeferredAload(false);
super.visitLabel(label);
}
@Override
public void visitLdcInsn(final Object cst) {
processDeferredAload(false);
super.visitLdcInsn(cst);
}
@Override
public void visitLineNumber(final int line, final Label start) {
processDeferredAload(false);
super.visitLineNumber(line, start);
}
@Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end, final int index) {
processDeferredAload(false);
super.visitLocalVariable(name, desc, signature, start, end, index);
}
@Override
public AnnotationVisitor visitLocalVariableAnnotation(final int typeRef,
final TypePath typePath, final Label[] start, final Label[] end,
final int[] index, final String desc, final boolean visible) {
processDeferredAload(false);
final AnnotationVisitor annotationVisitor =
super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index,
desc, visible);
return annotationVisitor;
}
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
processDeferredAload(false);
super.visitLookupSwitchInsn(dflt, keys, labels);
}
@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
processDeferredAload(false);
super.visitMaxs(maxStack, maxLocals);
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
processDeferredAload(false);
super.visitMethodInsn(opcode, owner, name, desc);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
processDeferredAload(false);
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
processDeferredAload(false);
super.visitMultiANewArrayInsn(desc, dims);
}
@Override
public void visitParameter(final String name, final int access) {
processDeferredAload(false);
super.visitParameter(name, access);
}
@Override
public AnnotationVisitor visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
processDeferredAload(false);
final AnnotationVisitor annotationVisitor =
super.visitParameterAnnotation(parameter, desc, visible);
return annotationVisitor;
}
@Override
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
processDeferredAload(false);
super.visitTableSwitchInsn(min, max, dflt, labels);
}
@Override
public AnnotationVisitor visitTryCatchAnnotation(final int typeRef,
final TypePath typePath, final String desc, final boolean visible) {
processDeferredAload(false);
final AnnotationVisitor annotationVisitor =
super.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
return annotationVisitor;
}
@Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
processDeferredAload(false);
super.visitTryCatchBlock(start, end, handler, type);
}
@Override
public AnnotationVisitor visitTypeAnnotation(final int typeRef,
final TypePath typePath, final String desc, final boolean visible) {
processDeferredAload(false);
final AnnotationVisitor annotationVisitor =
super.visitTypeAnnotation(typeRef, typePath, desc, visible);
return annotationVisitor;
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
processDeferredAload(false);
super.visitTypeInsn(opcode, type);
}
@Override
public void visitVarInsn(final int opcode, final int var) {
processDeferredAload(false);
// if we see an ALOAD, defer forwarding it until we know what the next instruction is
if (Opcodes.ALOAD == opcode) {
this.var = var;
} else {
super.visitVarInsn(opcode, var);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy