All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.drill.exec.compile.bytecode.ValueHolderIden 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 java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.cursors.ObjectIntCursor;
import com.google.common.collect.Lists;

class ValueHolderIden {
//  private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ValueHolderIden.class);

  // the index of a field is the number in which it appears within the holder
  private final ObjectIntHashMap fieldMap; // field name -> index
  private final Type[] types; // the type of each field in the holder, by index
  private final String[] names; // the name of each field in the holder, by index
  private final int[] offsets; // the offset of each field in the holder, by index
  private final Type type; // type of the holder itself

  public ValueHolderIden(Class c) {
    Field[] fields = c.getFields();

    // Find the non-static member variables
    List fldList = Lists.newArrayList();
    for (Field f : fields) {
      if (!Modifier.isStatic(f.getModifiers())) {
        fldList.add(f);
      }
    }

    this.type = Type.getType(c);

    this.types = new Type[fldList.size()];
    this.names = new String[fldList.size()];
    this.offsets = new int[fldList.size()];
    fieldMap = new ObjectIntHashMap(fldList.size());
    int i = 0; // index of the next holder member variable
    int offset = 0; // offset of the next holder member variable
    for (Field f : fldList) {
      types[i] = Type.getType(f.getType());
      names[i] = f.getName();
      offsets[i] = offset;
      fieldMap.put(f.getName(), i);

      // the next offset and index
      offset += types[i].getSize();
      i++;
    }
  }

  public void dump(final StringBuilder sb) {
    sb.append("ValueHolderIden: type=" + type + '\n');
    for (ObjectIntCursor oic : fieldMap) {
      sb.append("  " + oic.key + ": i=" + oic.value + ", type=" + types[oic.value] +
          ", offset=" + offsets[oic.value] + '\n');
    }
  }

  private static void initType(int offset, Type t, DirectSorter v) {
    switch(t.getSort()) {
    case Type.BOOLEAN:
    case Type.BYTE:
    case Type.CHAR:
    case Type.SHORT:
    case Type.INT:
      v.visitInsn(Opcodes.ICONST_0);
      v.directVarInsn(Opcodes.ISTORE, offset);
      break;
    case Type.LONG:
      v.visitInsn(Opcodes.LCONST_0);
      v.directVarInsn(Opcodes.LSTORE, offset);
      break;
    case Type.FLOAT:
      v.visitInsn(Opcodes.FCONST_0);
      v.directVarInsn(Opcodes.FSTORE, offset);
      break;
    case Type.DOUBLE:
      v.visitInsn(Opcodes.DCONST_0);
      v.directVarInsn(Opcodes.DSTORE, offset);
      break;
    case Type.OBJECT:
      v.visitInsn(Opcodes.ACONST_NULL);
      v.directVarInsn(Opcodes.ASTORE, offset);
      break;
    default:
      throw new UnsupportedOperationException();
    }
  }

  /**
   * Add the locals necessary to replace the members of a holder of this type.
   *
   * @param adder the method visitor to use to add the necessary instructions
   * @param defaultFirst the default index to return for the first variable
   *   if we don't find another one
   * @return the index of the first local variable (standing in for the first holder member)
   */
  private int addLocals(final DirectSorter adder, final int defaultFirst) {
    int first = defaultFirst;
    for (int i = 0; i < types.length; i++) {
      int varIndex = adder.newLocal(types[i]);
      if (i == 0) {
        first = varIndex; // first offset
      }
    }

    return first;
  }

  public ValueHolderSub getHolderSub(DirectSorter adder) {
    final int first = addLocals(adder, -1);
    return new ValueHolderSub(first);
  }

  public ValueHolderSub getHolderSubWithDefinedLocals(int first) {
    return new ValueHolderSub(first);
  }

  /**
   * Return the DUP or DUP2 opcode appropriate for the given type.
   *
   * @param type the type
   * @return the DUP/DUP2 opcode to use for type
   */
  private static int getDupOpcode(final Type type) {
    assert type.getSize() >= 1;
    return type.getSize() == 1 ? Opcodes.DUP : Opcodes.DUP2;
  }

  /**
   * Transfer the member variables of this holder to local variables.
   *
   * 

If this is used, the maximum stack size must be increased by one * to accommodate the extra DUP instruction this will generate. * * @param adder a visitor that will be called to add the necessary instructions * @param localVariable the offset of the first local variable to use */ public void transferToLocal(final DirectSorter adder, final int localVariable) { for (int i = 0; i < types.length; i++) { final Type t = types[i]; if (i + 1 < types.length) { adder.visitInsn(Opcodes.DUP); // not size dependent: always the objectref from which we'll GETFIELD } adder.visitFieldInsn(Opcodes.GETFIELD, type.getInternalName(), names[i], t.getDescriptor()); adder.directVarInsn(t.getOpcode(Opcodes.ISTORE), localVariable + offsets[i]); } } /** * Create local variables and transfer the members of a holder to them. * * @param adder the method visitor to use to add the variables * @return the index of the first variable added */ public int createLocalAndTransfer(final DirectSorter adder) { final int first = addLocals(adder, 0); transferToLocal(adder, first); return first; } public class ValueHolderSub { private int first; // TODO: deal with transfer() so this can be made final @Override public String toString() { return "ValueHolderSub(" + first + ")"; } public ValueHolderSub(int first) { assert first != -1 : "Create Holder for sub that doesn't have any fields."; this.first = first; } public ValueHolderIden iden() { return ValueHolderIden.this; } public void init(DirectSorter mv) { for (int i = 0; i < types.length; i++) { initType(first + offsets[i], types[i], mv); } } public int first() { return first; } private int getFieldIndex(final String name, final InstructionModifier mv) { if (!fieldMap.containsKey(name)) { throw new IllegalArgumentException(String.format( "Unknown name '%s' on line %d.", name, mv.getLastLineNumber())); } return fieldMap.get(name); // using lget() is not thread-safe } public void addInsn(String name, InstructionModifier mv, int opcode) { switch (opcode) { case Opcodes.GETFIELD: addKnownInsn(name, mv, Opcodes.ILOAD); return; case Opcodes.PUTFIELD: addKnownInsn(name, mv, Opcodes.ISTORE); } } // TODO: do we really need this? Instead of moving the variables, can't we just // use the original locations in the subsequent references? public void transfer(InstructionModifier mv, int newStart) { // if the new location is the same as the current position, there's nothing to do if (first == newStart) { return; } for (int i = 0; i < types.length; i++) { mv.directVarInsn(types[i].getOpcode(Opcodes.ILOAD), first + offsets[i]); mv.directVarInsn(types[i].getOpcode(Opcodes.ISTORE), newStart + offsets[i]); } this.first = newStart; } private void addKnownInsn(String name, InstructionModifier mv, int analogOpcode) { int f = getFieldIndex(name, mv); Type t = types[f]; mv.directVarInsn(t.getOpcode(analogOpcode), first + offsets[f]); } /** * * @param adder * @param owner * @param name * @param desc * @return amount of additional stack space that will be required for this instruction stream */ public int transferToExternal(final DirectSorter adder, final String owner, final String name, final String desc) { // create a new object and assign it to the desired field. adder.visitTypeInsn(Opcodes.NEW, type.getInternalName()); adder.visitInsn(getDupOpcode(type)); adder.visitMethodInsn(Opcodes.INVOKESPECIAL, type.getInternalName(), "", "()V", false); // now we need to set all of the values of this new object. int additionalStack = 0; for (int i = 0; i < types.length; i++) { final Type t = types[i]; // dup the object where we are putting the field. adder.visitInsn(getDupOpcode(type)); // dup for every as we want to save in place at end. adder.directVarInsn(t.getOpcode(Opcodes.ILOAD), first + offsets[i]); adder.visitFieldInsn(Opcodes.PUTFIELD, type.getInternalName(), names[i], t.getDescriptor()); /* * The above substitutes a reference to a scalar in a holder with a direct reference to * the scalar. * * In the case of longs or doubles, this requires more stack space than was used before; * if we were moving a reference to a holder with a long, we were previously moving the * reference. But now we're moving the long, which is twice as big. So we may need more * stack space than has currently been allocated. */ if (t.getSize() > additionalStack) { additionalStack = t.getSize(); } } // lastly we save it to the desired field. adder.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc); return additionalStack; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy