Package org.apache.drill.exec.compile.bytecode

Source Code of org.apache.drill.exec.compile.bytecode.InstructionModifier

/**
* 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.apache.drill.exec.compile.bytecode.ValueHolderIden.ValueHolderSub;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import com.carrotsearch.hppc.IntIntOpenHashMap;
import com.carrotsearch.hppc.IntObjectOpenHashMap;

public class InstructionModifier extends MethodVisitor {
  static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(InstructionModifier.class);

  private final IntObjectOpenHashMap<ValueHolderIden.ValueHolderSub> oldToNew = new IntObjectOpenHashMap<>();
  private final IntIntOpenHashMap oldLocalToFirst = new IntIntOpenHashMap();

  private DirectSorter adder;
  int lastLineNumber = 0;
  private TrackingInstructionList list;

  public InstructionModifier(int access, String name, String desc, String signature, String[] exceptions,
      TrackingInstructionList list, MethodVisitor inner) {
    super(Opcodes.ASM4, new DirectSorter(access, desc, inner));
    this.list = list;
    this.adder = (DirectSorter) mv;
  }

  public void setList(TrackingInstructionList list) {
    this.list = list;
  }

  private ReplacingBasicValue local(int var) {
    Object o = list.currentFrame.getLocal(var);
    if (o instanceof ReplacingBasicValue) {
      return (ReplacingBasicValue) o;
    }
    return null;
  }

  private ReplacingBasicValue popCurrent() {
    return popCurrent(false);
  }

  private ReplacingBasicValue popCurrent(boolean includeReturnVals) {
    // for vararg, we could try to pop an empty stack. TODO: handle this better.
    if (list.currentFrame.getStackSize() == 0) {
      return null;
    }

    Object o = list.currentFrame.pop();
    if (o instanceof ReplacingBasicValue) {
      ReplacingBasicValue v = (ReplacingBasicValue) o;
      if (!v.isFunctionReturn || includeReturnVals) {
        return v;
      }
    }
    return null;
  }

  private ReplacingBasicValue getReturn() {
    Object o = list.nextFrame.getStack(list.nextFrame.getStackSize() - 1);
    if (o instanceof ReplacingBasicValue) {
      return (ReplacingBasicValue) o;
    }
    return null;
  }

  @Override
  public void visitInsn(int opcode) {
    switch (opcode) {
    case Opcodes.DUP:
      if (popCurrent() != null) {
        return;
      }
    }
    super.visitInsn(opcode);
  }

  @Override
  public void visitTypeInsn(int opcode, String type) {
    ReplacingBasicValue r = getReturn();
    if (r != null) {
      ValueHolderSub sub = r.getIden().getHolderSub(adder);
      oldToNew.put(r.getIndex(), sub);
    } else {
      super.visitTypeInsn(opcode, type);
    }
  }

  @Override
  public void visitLineNumber(int line, Label start) {
    lastLineNumber = line;
    super.visitLineNumber(line, start);
  }

  @Override
  public void visitVarInsn(int opcode, int var) {
    ReplacingBasicValue v;
    if (opcode == Opcodes.ASTORE && (v = popCurrent(true)) != null) {
      if (!v.isFunctionReturn) {
        ValueHolderSub from = oldToNew.get(v.getIndex());

        ReplacingBasicValue current = local(var);
        // if local var is set, then transfer to it to the existing holders in the local position.
        if (current != null) {
          if (oldToNew.get(current.getIndex()).iden() == from.iden()) {
            int targetFirst = oldToNew.get(current.index).first();
            from.transfer(this, targetFirst);
            return;
          }
        }

        // if local var is not set, then check map to see if existing holders are mapped to local var.
        if (oldLocalToFirst.containsKey(var)) {
          ValueHolderSub sub = oldToNew.get(oldLocalToFirst.lget());
          if (sub.iden() == from.iden()) {
            // if they are, then transfer to that.
            from.transfer(this, oldToNew.get(oldLocalToFirst.lget()).first());
            return;
          }
        }


        // map from variables to global space for future use.
        oldLocalToFirst.put(var, v.getIndex());

      } else {
        // this is storage of a function return, we need to map the fields to the holder spots.
        int first;
        if (oldLocalToFirst.containsKey(var)) {
          first = oldToNew.get(oldLocalToFirst.lget()).first();
          v.iden.transferToLocal(adder, first);
        } else {
          first = v.iden.createLocalAndTrasfer(adder);
        }
        ValueHolderSub from = v.iden.getHolderSubWithDefinedLocals(first);
        oldToNew.put(v.getIndex(), from);
        v.disableFunctionReturn();
      }

    } else if (opcode == Opcodes.ALOAD && (v = getReturn()) != null) {
      // noop.
    } else {
      super.visitVarInsn(opcode, var);
    }

  }

  void directVarInsn(int opcode, int var) {
    adder.directVarInsn(opcode, var);
  }

  @Override
  public void visitFieldInsn(int opcode, String owner, String name, String desc) {
    ReplacingBasicValue v;

    switch (opcode) {
    case Opcodes.PUTFIELD:
      // pop twice for put.
      v = popCurrent(true);
      if (v != null) {
        if (v.isFunctionReturn) {
          super.visitFieldInsn(opcode, owner, name, desc);
          return;
        } else {
          // we are trying to store a replaced variable in an external context, we need to generate an instance and
          // transfer it out.
          ValueHolderSub sub = oldToNew.get(v.getIndex());
          sub.transferToExternal(adder, owner, name, desc);
          return;
        }
      }

    case Opcodes.GETFIELD:
      // pop again.
      v = popCurrent();
      if (v != null) {
        // super.visitFieldInsn(opcode, owner, name, desc);
        ValueHolderSub sub = oldToNew.get(v.getIndex());
        sub.addInsn(name, this, opcode);
        return;
      }
    }

    super.visitFieldInsn(opcode, owner, name, desc);
  }

  @Override
  public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
    // if (!ReplacingInterpreter.HOLDER_DESCRIPTORS.contains(desc)) {
    // super.visitLocalVariable(name, desc, signature, start, end, index);
    // }
  }

  @Override
  public void visitMethodInsn(int opcode, String owner, String name, String desc) {
    final int len = Type.getArgumentTypes(desc).length;
    final boolean isStatic = opcode == Opcodes.INVOKESTATIC;

    ReplacingBasicValue obj = popCurrent();

    if (obj != null && !isStatic) {
      if ("<init>".equals(name)) {
        oldToNew.get(obj.getIndex()).init(adder);
      } else {
        throw new IllegalStateException("you can't call a method on a value holder.");
      }
      return;
    }

    obj = getReturn();

    if (obj != null) {
      // the return of this method is an actual instance of the object we're escaping. Update so that it get's mapped
      // correctly.
      super.visitMethodInsn(opcode, owner, name, desc);
      obj.markFunctionReturn();
      return;
    }

    int i = isStatic ? 1 : 0;
    for (; i < len; i++) {
      checkArg(name, popCurrent());
    }

    super.visitMethodInsn(opcode, owner, name, desc);
  }

  private void checkArg(String name, ReplacingBasicValue obj) {
    if (obj == null) {
      return;
    }
    throw new IllegalStateException(
        String
            .format(
                "Holder types are not allowed to be passed between methods.  Ran across problem attempting to invoke method '%s' on line number %d",
                name, lastLineNumber));
  }

}
TOP

Related Classes of org.apache.drill.exec.compile.bytecode.InstructionModifier

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.