blob: d594044d676fb722f6479008829a7cbbd10addb1 [file] [log] [blame]
/*
* 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 java.util.List;
import org.apache.drill.exec.compile.CompilationConfig;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.BasicInterpreter;
import org.objectweb.asm.tree.analysis.BasicValue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
public class ReplacingInterpreter extends BasicInterpreter {
// private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ReplacingInterpreter.class);
private final String className; // fully qualified internal class name
private int index = 0;
private final List<ReplacingBasicValue> valueList;
public ReplacingInterpreter(final String className, final List<ReplacingBasicValue> valueList) {
super(CompilationConfig.ASM_API_VERSION);
this.className = className;
this.valueList = valueList;
}
@Override
public BasicValue newValue(final Type t) {
if (t != null) {
final ValueHolderIden iden = HOLDERS.get(t.getDescriptor());
if (iden != null) {
final ReplacingBasicValue v = ReplacingBasicValue.create(t, iden, index++, valueList);
v.markFunctionReturn();
return v;
}
// We need to track use of the "this" objectref
if ((t.getSort() == Type.OBJECT) && className.equals(t.getInternalName())) {
final ReplacingBasicValue rbValue = ReplacingBasicValue.create(t, null, 0, valueList);
rbValue.setThis();
return rbValue;
}
}
return super.newValue(t);
}
@Override
public BasicValue newOperation(final AbstractInsnNode insn) throws AnalyzerException {
if (insn.getOpcode() == Opcodes.NEW) {
final TypeInsnNode t = (TypeInsnNode) insn;
// if this is for a holder class, we'll replace it
final ValueHolderIden iden = HOLDERS.get(t.desc);
if (iden != null) {
return ReplacingBasicValue.create(Type.getObjectType(t.desc), iden, index++, valueList);
}
}
return super.newOperation(insn);
}
@Override
public void returnOperation(AbstractInsnNode insn, BasicValue value, BasicValue expected) {
if (value instanceof ReplacingBasicValue) {
((ReplacingBasicValue) value).markFunctionReturn();
}
}
@Override
public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value)
throws AnalyzerException {
/*
* We're looking for the assignment of an operator member variable that's a holder to a local
* objectref. If we spot that, we can't replace the local objectref (at least not
* until we do the work to replace member variable holders).
*
* Note that a GETFIELD does not call newValue(), as would happen for a local variable, so we're
* emulating that here.
*/
if ((insn.getOpcode() == Opcodes.GETFIELD) && (value instanceof ReplacingBasicValue)) {
final ReplacingBasicValue possibleThis = (ReplacingBasicValue) value;
if (possibleThis.isThis()) {
final FieldInsnNode fieldInsn = (FieldInsnNode) insn;
if (HOLDERS.get(fieldInsn.desc) != null) {
final BasicValue fetchedField = super.unaryOperation(insn, value);
final ReplacingBasicValue replacingValue =
ReplacingBasicValue.create(fetchedField.getType(), null, -1, valueList);
replacingValue.setAssignedToMember();
return replacingValue;
}
}
}
return super.unaryOperation(insn, value);
}
@Override
public BasicValue binaryOperation(final AbstractInsnNode insn,
final BasicValue value1, final BasicValue value2) throws AnalyzerException {
/*
* We're looking for the assignment of a local holder objectref to a member variable.
* If we spot that, then the local holder can't be replaced, since we don't (yet)
* have the mechanics to replace the member variable with the holder's members or
* to assign all of them when this happens.
*/
if (insn.getOpcode() == Opcodes.PUTFIELD) {
if (value2.isReference() && (value1 instanceof ReplacingBasicValue)) {
final ReplacingBasicValue possibleThis = (ReplacingBasicValue) value1;
if (possibleThis.isThis() && (value2 instanceof ReplacingBasicValue)) {
// if this is a reference for a holder class, we can't replace it
if (HOLDERS.get(value2.getType().getDescriptor()) != null) {
final ReplacingBasicValue localRef = (ReplacingBasicValue) value2;
localRef.setAssignedToMember();
}
}
}
}
return super.binaryOperation(insn, value1, value2);
}
@Override
public BasicValue naryOperation(final AbstractInsnNode insn,
final List<? extends BasicValue> values) throws AnalyzerException {
if (insn instanceof MethodInsnNode) {
boolean skipOne = insn.getOpcode() != Opcodes.INVOKESTATIC;
// Note if the argument is a holder, and is used as a function argument
for(BasicValue value : values) {
// if non-static method, skip over the receiver
if (skipOne) {
skipOne = false;
continue;
}
if (value instanceof ReplacingBasicValue) {
final ReplacingBasicValue argument = (ReplacingBasicValue) value;
argument.setFunctionArgument();
}
}
}
return super.naryOperation(insn, values);
}
@Override
public BasicValue ternaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2, BasicValue value3) throws AnalyzerException {
// prevents scalar replacement for the case when a holder is stored to the array element
if (insn.getOpcode() == AASTORE && value3 instanceof ReplacingBasicValue) {
ReplacingBasicValue argument = (ReplacingBasicValue) value3;
argument.setAssignedToMember();
}
return super.ternaryOperation(insn, value1, value2, value3);
}
private static String desc(Class<?> c) {
final Type t = Type.getType(c);
return t.getDescriptor();
}
static {
ImmutableMap.Builder<String, ValueHolderIden> builder = ImmutableMap.builder();
ImmutableSet.Builder<String> setB = ImmutableSet.builder();
for (Class<?> c : ScalarReplacementTypes.CLASSES) {
String desc = desc(c);
setB.add(desc);
String desc2 = desc.substring(1, desc.length() - 1);
ValueHolderIden vhi = new ValueHolderIden(c);
builder.put(desc, vhi);
builder.put(desc2, vhi);
}
HOLDER_DESCRIPTORS = setB.build();
HOLDERS = builder.build();
}
private final static ImmutableMap<String, ValueHolderIden> HOLDERS;
public final static ImmutableSet<String> HOLDER_DESCRIPTORS;
}