Class<?> defineClass(String name, byte[] b) {
      return defineClass(name, b, 0, b.length);
    }
  }

  private java.lang.Class loadClass(String className, byte[] b) throws Exception {
    /**
     * This must be synchronized.  Two classes cannot be simultaneously deployed in the JVM.
     */
    ContextClassLoader contextClassLoader = getContextClassLoader();
    return contextClassLoader == null ?
            classLoader.defineClassX(className, b, 0, b.length) :
            contextClassLoader.defineClass(className, b);
  }

  private boolean debug(String instruction) {
    if (buildLog != null) {
      buildLog.append(instruction).append("\n");
    }
    return true;
  }

  @SuppressWarnings({"SameReturnValue"})
  public String getName() {
    return "ASM";
  }

  public Object getResultOptPass() {
    return val;
  }

  private Class getWrapperClass(Class cls) {
    if (cls == boolean.class) {
      return Boolean.class;
    }
    else if (cls == int.class) {
      return Integer.class;
    }
    else if (cls == float.class) {
      return Float.class;
    }
    else if (cls == double.class) {
      return Double.class;
    }
    else if (cls == short.class) {
      return Short.class;
    }
    else if (cls == long.class) {
      return Long.class;
    }
    else if (cls == byte.class) {
      return Byte.class;
    }
    else if (cls == char.class) {
      return Character.class;
    }

    return cls;
  }

  private void unwrapPrimitive(Class cls) {
    if (cls == boolean.class) {
      assert debug("CHECKCAST java/lang/Boolean");
      mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
      assert debug("INVOKEVIRTUAL java/lang/Boolean.booleanValue");
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
    }
    else if (cls == int.class) {
      assert debug("CHECKCAST java/lang/Integer");
      mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
      assert debug("INVOKEVIRTUAL java/lang/Integer.intValue");
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
    }
    else if (cls == float.class) {
      assert debug("CHECKCAST java/lang/Float");
      mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
      assert debug("INVOKEVIRTUAL java/lang/Float.floatValue");
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
    }
    else if (cls == double.class) {
      assert debug("CHECKCAST java/lang/Double");
      mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
      assert debug("INVOKEVIRTUAL java/lang/Double.doubleValue");
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
    }
    else if (cls == short.class) {
      assert debug("CHECKCAST java/lang/Short");
      mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
      assert debug("INVOKEVIRTUAL java/lang/Short.shortValue");
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
    }
    else if (cls == long.class) {
      assert debug("CHECKCAST java/lang/Long");
      mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
      assert debug("INVOKEVIRTUAL java/lang/Long.longValue");
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
    }
    else if (cls == byte.class) {
      assert debug("CHECKCAST java/lang/Byte");
      mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
      assert debug("INVOKEVIRTUAL java/lang/Byte.byteValue");
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
    }
    else if (cls == char.class) {
      assert debug("CHECKCAST java/lang/Character");
      mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
      assert debug("INVOKEVIRTUAL java/lang/Character.charValue");
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
    }
  }


  private void wrapPrimitive(Class<? extends Object> cls) {
    if (OPCODES_VERSION == Opcodes.V1_4) {
      /**
       * JAVA 1.4 SUCKS!  DIE 1.4 DIE!!!
       */

      debug("** Using 1.4 Bytecode **");

      if (cls == boolean.class || cls == Boolean.class) {
        debug("NEW java/lang/Boolean");
        mv.visitTypeInsn(NEW, "java/lang/Boolean");

        debug("DUP X1");
        mv.visitInsn(DUP_X1);

        debug("SWAP");
        mv.visitInsn(SWAP);

        debug("INVOKESPECIAL java/lang/Boolean.<init>::(Z)V");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Boolean", "<init>", "(Z)V");
      }
      else if (cls == int.class || cls == Integer.class) {
        debug("NEW java/lang/Integer");
        mv.visitTypeInsn(NEW, "java/lang/Integer");

        debug("DUP X1");
        mv.visitInsn(DUP_X1);

        debug("SWAP");
        mv.visitInsn(SWAP);

        debug("INVOKESPECIAL java/lang/Integer.<init>::(I)V");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer", "<init>", "(I)V");
      }
      else if (cls == float.class || cls == Float.class) {
        debug("NEW java/lang/Float");
        mv.visitTypeInsn(NEW, "java/lang/Float");

        debug("DUP X1");
        mv.visitInsn(DUP_X1);

        debug("SWAP");
        mv.visitInsn(SWAP);

        debug("INVOKESPECIAL java/lang/Float.<init>::(F)V");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Float", "<init>", "(F)V");
      }
      else if (cls == double.class || cls == Double.class) {
        debug("NEW java/lang/Double");
        mv.visitTypeInsn(NEW, "java/lang/Double");

        debug("DUP X2");
        mv.visitInsn(DUP_X2);

        debug("DUP X2");
        mv.visitInsn(DUP_X2);

        debug("POP");
        mv.visitInsn(POP);

        debug("INVOKESPECIAL java/lang/Double.<init>::(D)V");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Double", "<init>", "(D)V");
      }
      else if (cls == short.class || cls == Short.class) {
        debug("NEW java/lang/Short");
        mv.visitTypeInsn(NEW, "java/lang/Short");

        debug("DUP X1");
        mv.visitInsn(DUP_X1);

        debug("SWAP");
        mv.visitInsn(SWAP);

        debug("INVOKESPECIAL java/lang/Short.<init>::(S)V");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Short", "<init>", "(S)V");
      }
      else if (cls == long.class || cls == Long.class) {
        debug("NEW java/lang/Long");
        mv.visitTypeInsn(NEW, "java/lang/Long");

        debug("DUP X1");
        mv.visitInsn(DUP_X1);

        debug("SWAP");
        mv.visitInsn(SWAP);

        debug("INVOKESPECIAL java/lang/Long.<init>::(L)V");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Float", "<init>", "(L)V");
      }
      else if (cls == byte.class || cls == Byte.class) {
        debug("NEW java/lang/Byte");
        mv.visitTypeInsn(NEW, "java/lang/Byte");

        debug("DUP X1");
        mv.visitInsn(DUP_X1);

        debug("SWAP");
        mv.visitInsn(SWAP);

        debug("INVOKESPECIAL java/lang/Byte.<init>::(B)V");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Byte", "<init>", "(B)V");
      }
      else if (cls == char.class || cls == Character.class) {
        debug("NEW java/lang/Character");
        mv.visitTypeInsn(NEW, "java/lang/Character");

        debug("DUP X1");
        mv.visitInsn(DUP_X1);

        debug("SWAP");
        mv.visitInsn(SWAP);

        debug("INVOKESPECIAL java/lang/Character.<init>::(C)V");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Character", "<init>", "(C)V");
      }
    }
    else {
      if (cls == boolean.class || cls == Boolean.class) {
        debug("INVOKESTATIC java/lang/Boolean.valueOf");
        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
      }
      else if (cls == int.class || cls == Integer.class) {
        debug("INVOKESTATIC java/lang/Integer.valueOf");
        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
      }
      else if (cls == float.class || cls == Float.class) {
        debug("INVOKESTATIC java/lang/Float.valueOf");
        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
      }
      else if (cls == double.class || cls == Double.class) {
        debug("INVOKESTATIC java/lang/Double.valueOf");
        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
      }
      else if (cls == short.class || cls == Short.class) {
        debug("INVOKESTATIC java/lang/Short.valueOf");
        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
      }
      else if (cls == long.class || cls == Long.class) {
        debug("INVOKESTATIC java/lang/Long.valueOf");
        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
      }
      else if (cls == byte.class || cls == Byte.class) {
        debug("INVOKESTATIC java/lang/Byte.valueOf");
        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
      }
      else if (cls == char.class || cls == Character.class) {
        debug("INVOKESTATIC java/lang/Character.valueOf");
        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
      }
    }
  }

  private void anyArrayCheck(Class cls) {
    if (cls == boolean[].class) {
      assert debug("CHECKCAST [Z");
      mv.visitTypeInsn(CHECKCAST, "[Z");
    }
    else if (cls == int[].class) {
      assert debug("CHECKCAST [I");
      mv.visitTypeInsn(CHECKCAST, "[I");
    }
    else if (cls == float[].class) {
      assert debug("CHECKCAST [F");
      mv.visitTypeInsn(CHECKCAST, "[F");
    }
    else if (cls == double[].class) {
      assert debug("CHECKCAST [D");
      mv.visitTypeInsn(CHECKCAST, "[D");
    }
    else if (cls == short[].class) {
      assert debug("CHECKCAST [S");
      mv.visitTypeInsn(CHECKCAST, "[S");
    }
    else if (cls == long[].class) {
      assert debug("CHECKCAST [J");
      mv.visitTypeInsn(CHECKCAST, "[J");
    }
    else if (cls == byte[].class) {
      assert debug("CHECKCAST [B");
      mv.visitTypeInsn(CHECKCAST, "[B");
    }
    else if (cls == char[].class) {
      assert debug("CHECKCAST [C");
      mv.visitTypeInsn(CHECKCAST, "[C");
    }
    else {
      assert debug("CHECKCAST [Ljava/lang/Object;");
      mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
    }
  }

  private void writeOutLiteralWrapped(Object lit) {
    if (lit instanceof Integer) {
      intPush((Integer) lit);
      wrapPrimitive(int.class);
      return;
    }

    assert debug("LDC " + lit);
    if (lit instanceof String) {
      mv.visitLdcInsn(lit);
    }
    else if (lit instanceof Long) {
      mv.visitLdcInsn(lit);
      wrapPrimitive(long.class);
    }
    else if (lit instanceof Float) {
      mv.visitLdcInsn(lit);
      wrapPrimitive(float.class);
    }
    else if (lit instanceof Double) {
      mv.visitLdcInsn(lit);
      wrapPrimitive(double.class);
    }
    else if (lit instanceof Short) {
      mv.visitLdcInsn(lit);
      wrapPrimitive(short.class);
    }
    else if (lit instanceof Character) {
      mv.visitLdcInsn(lit);
      wrapPrimitive(char.class);
    }
    else if (lit instanceof Boolean) {
      mv.visitLdcInsn(lit);
      wrapPrimitive(boolean.class);
    }
    else if (lit instanceof Byte) {
      mv.visitLdcInsn(lit);
      wrapPrimitive(byte.class);
    }
  }

  public void arrayStore(Class cls) {
    if (cls.isPrimitive()) {
      if (cls == int.class) {
        assert debug("IASTORE");
        mv.visitInsn(IASTORE);
      }
      else if (cls == char.class) {
        assert debug("CASTORE");
        mv.visitInsn(CASTORE);
      }
      else if (cls == boolean.class) {
        assert debug("BASTORE");
        mv.visitInsn(BASTORE);
      }
      else if (cls == double.class) {
        assert debug("DASTORE");
        mv.visitInsn(DASTORE);
      }
      else if (cls == float.class) {
        assert debug("FASTORE");
        mv.visitInsn(FASTORE);
      }
      else if (cls == short.class) {
        assert debug("SASTORE");
        mv.visitInsn(SASTORE);
      }
      else if (cls == long.class) {
        assert debug("LASTORE");
        mv.visitInsn(LASTORE);
      }
      else if (cls == byte.class) {
        assert debug("BASTORE");
        mv.visitInsn(BASTORE);
      }
    }
    else {
      assert debug("AASTORE");
      mv.visitInsn(AASTORE);
    }

  }

  public void wrapRuntimeConverstion(Class toType) {
    ldcClassConstant(getWrapperClass(toType));

    assert debug("INVOKESTATIC DataConversion.convert");
    mv.visitMethodInsn(INVOKESTATIC, "" + NAMESPACE + "DataConversion", "convert",
        "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
  }


  private Object addSubstatement(ExecutableStatement stmt) {
    if (stmt instanceof ExecutableAccessor) {
      ExecutableAccessor ea = (ExecutableAccessor) stmt;
      if (ea.getNode().isIdentifier() && !ea.getNode().isDeepProperty()) {
        loadVariableByName(ea.getNode().getName());
        return null;
      }
    }

    compiledInputs.add(stmt);

    assert debug("ALOAD 0");
    mv.visitVarInsn(ALOAD, 0);

    assert debug("GETFIELD p" + (compiledInputs.size() - 1));
    mv.visitFieldInsn(GETFIELD, className, "p" + (compiledInputs.size() - 1),
        "L" + NAMESPACE + "compiler/ExecutableStatement;");

    assert debug("ALOAD 2");
    mv.visitVarInsn(ALOAD, 2);

    assert debug("ALOAD 3");
    mv.visitVarInsn(ALOAD, 3);

    assert debug("INVOKEINTERFACE ExecutableStatement.getValue");
    mv.visitMethodInsn(INVOKEINTERFACE, getInternalName(ExecutableStatement.class), "getValue",
        "(Ljava/lang/Object;L" + NAMESPACE + "integration/VariableResolverFactory;)Ljava/lang/Object;");

    return null;
  }


  private void loadVariableByName(String name) {
    assert debug("ALOAD 3");
    mv.visitVarInsn(ALOAD, 3);

    assert debug("LDC \"" + name + "\"");
    mv.visitLdcInsn(name);

    assert debug("INVOKEINTERFACE " + NAMESPACE + "integration/VariableResolverFactory.getVariableResolver");
    mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE + "integration/VariableResolverFactory",
        "getVariableResolver", "(Ljava/lang/String;)L" + NAMESPACE + "integration/VariableResolver;");

    assert debug("INVOKEINTERFACE " + NAMESPACE + "integration/VariableResolver.getValue");
    mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE + "integration/VariableResolver",
        "getValue", "()Ljava/lang/Object;");

    returnType = Object.class;
  }

  private void loadVariableByIndex(int pos) {
    assert debug("ALOAD 3");
    mv.visitVarInsn(ALOAD, 3);

    assert debug("PUSH IDX VAL =" + pos);
    intPush(pos);

    assert debug("INVOKEINTERFACE " + NAMESPACE + "integration/VariableResolverFactory.getIndexedVariableResolver");
    mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE + "integration/VariableResolverFactory",
        "getIndexedVariableResolver", "(I)L" + NAMESPACE + "integration/VariableResolver;");

    assert debug("INVOKEINTERFACE " + NAMESPACE + "integration/VariableResolver.getValue");
    mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE + "integration/VariableResolver",
        "getValue", "()Ljava/lang/Object;");

    returnType = Object.class;
  }

  private void loadField(int number) {
    assert debug("ALOAD 0");
    mv.visitVarInsn(ALOAD, 0);

    assert debug("GETFIELD p" + number);
    mv.visitFieldInsn(GETFIELD, className, "p" + number, "L" + NAMESPACE + "compiler/ExecutableStatement;");
  }

  private void ldcClassConstant(Class cls) {
    if (OPCODES_VERSION == Opcodes.V1_4) {
      assert debug("LDC \"" + cls.getName() + "\"");
      mv.visitLdcInsn(cls.getName());
      mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
      Label l4 = new Label();
      mv.visitJumpInsn(GOTO, l4);
      mv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
      mv.visitInsn(DUP_X1);
      mv.visitInsn(SWAP);
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "getMessage", "()Ljava/lang/String;");
      mv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V");
      mv.visitInsn(ATHROW);
      mv.visitLabel(l4);
    }
    else {
      assert debug("LDC " + getType(cls));
      mv.visitLdcInsn(getType(cls));
    }
  }

  private void buildInputs() {
    if (compiledInputs.size() == 0) return;

    assert debug("\n{SETTING UP MEMBERS...}\n");

    StringAppender constSig = new StringAppender("(");
    int size = compiledInputs.size();

    for (int i = 0; i < size; i++) {
      assert debug("ACC_PRIVATE p" + i);
      cw.visitField(ACC_PRIVATE, "p" + i, "L" + NAMESPACE + "compiler/ExecutableStatement;", null, null).visitEnd();

      constSig.append("L" + NAMESPACE + "compiler/ExecutableStatement;");
    }
    constSig.append(")V");

    assert debug("\n{CREATING INJECTION CONSTRUCTOR}\n");

    MethodVisitor cv = cw.visitMethod(ACC_PUBLIC, "<init>", constSig.toString(), null, null);
    cv.visitCode();
    assert debug("ALOAD 0");
    cv.visitVarInsn(ALOAD, 0);
    assert debug("INVOKESPECIAL java/lang/Object.<init>");
    cv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");

    for (int i = 0; i < size; i++) {
      assert debug("ALOAD 0");
      cv.visitVarInsn(ALOAD, 0);
      assert debug("ALOAD " + (i + 1));
      cv.visitVarInsn(ALOAD, i + 1);
      assert debug("PUTFIELD p" + i);
      cv.visitFieldInsn(PUTFIELD, className, "p" + i, "L" + NAMESPACE + "compiler/ExecutableStatement;");
    }

    assert debug("RETURN");
    cv.visitInsn(RETURN);
    cv.visitMaxs(0, 0);
    cv.visitEnd();

    assert debug("}");
  }

  private static final int ARRAY = 0;
  private static final int LIST = 1;
  private static final int MAP = 2;
  private static final int VAL = 3;

  private int _getAccessor(Object o, Class type) {
    if (o instanceof List) {
      assert debug("NEW " + LIST_IMPL);
      mv.visitTypeInsn(NEW, LIST_IMPL);

      assert debug("DUP");
      mv.visitInsn(DUP);

      assert debug("DUP");
      mv.visitInsn(DUP);

      intPush(((List) o).size());
      assert debug("INVOKESPECIAL " + LIST_IMPL + ".<init>");
      mv.visitMethodInsn(INVOKESPECIAL, LIST_IMPL, "<init>", "(I)V");

      for (Object item : (List) o) {
        if (_getAccessor(item, type) != VAL) {
          assert debug("POP");
          mv.visitInsn(POP);
        }

        assert debug("INVOKEINTERFACE java/util/List.add");
        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z");

        assert debug("POP");
        mv.visitInsn(POP);

        assert debug("DUP");
        mv.visitInsn(DUP);
      }

      returnType = List.class;

      return LIST;
    }
    else if (o instanceof Map) {
      assert debug("NEW " + MAP_IMPL);
      mv.visitTypeInsn(NEW, MAP_IMPL);

      assert debug("DUP");
      mv.visitInsn(DUP);

      assert debug("DUP");
      mv.visitInsn(DUP);

      intPush(((Map) o).size());

      assert debug("INVOKESPECIAL " + MAP_IMPL + ".<init>");
      mv.visitMethodInsn(INVOKESPECIAL, MAP_IMPL, "<init>", "(I)V");

      for (Object item : ((Map) o).keySet()) {
        mv.visitTypeInsn(CHECKCAST, "java/util/Map");

        if (_getAccessor(item, type) != VAL) {
          assert debug("POP");
          mv.visitInsn(POP);
        }
        if (_getAccessor(((Map) o).get(item), type) != VAL) {
          assert debug("POP");
          mv.visitInsn(POP);
        }

        assert debug("INVOKEINTERFACE java/util/Map.put");
        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "put",
            "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

        assert debug("POP");
        mv.visitInsn(POP);

        assert debug("DUP");
        mv.visitInsn(DUP);
      }

      returnType = Map.class;

      return MAP;
    }
    else if (o instanceof Object[]) {
      Accessor[] a = new Accessor[((Object[]) o).length];
      int i = 0;
      int dim = 0;

      if (type != null) {
        String nm = type.getName();
        while (nm.charAt(dim) == '[') dim++;
      }
      else {
        type = Object[].class;
        dim = 1;
      }

      try {
        intPush(((Object[]) o).length);
        assert debug("ANEWARRAY " + getInternalName(getSubComponentType(type)) + " (" + ((Object[]) o).length + ")");
        mv.visitTypeInsn(ANEWARRAY, getInternalName(getSubComponentType(type)));

        Class cls = dim > 1 ? findClass(null, repeatChar('[', dim - 1)
            + "L" + getBaseComponentType(type).getName() + ";", pCtx)
            : type;


        assert debug("DUP");
        mv.visitInsn(DUP);

        for (Object item : (Object[]) o) {
          intPush(i);

          if (_getAccessor(item, cls) != VAL) {
            assert debug("POP");
            mv.visitInsn(POP);
          }

          assert debug("AASTORE (" + o.hashCode() + ")");
          mv.visitInsn(AASTORE);

          assert debug("DUP");
          mv.visitInsn(DUP);

          i++;
        }

      }
      catch (ClassNotFoundException e) {
        throw new RuntimeException("this error should never throw:" + getBaseComponentType(type).getName(), e);
      }

      return ARRAY;
    }
    else {
      if (type.isArray()) {
        writeLiteralOrSubexpression(subCompileExpression(((String) o).toCharArray(), pCtx), getSubComponentType(type));
      }
      else {
        writeLiteralOrSubexpression(subCompileExpression(((String) o).toCharArray(), pCtx));
      }
      return VAL;
    }
  }

  private Class writeLiteralOrSubexpression(Object stmt) {
    return writeLiteralOrSubexpression(stmt, null, null);
  }

  private Class writeLiteralOrSubexpression(Object stmt, Class desiredTarget) {
    return writeLiteralOrSubexpression(stmt, desiredTarget, null);
  }

  private Class writeLiteralOrSubexpression(Object stmt, Class desiredTarget, Class knownIngressType) {
    if (stmt instanceof ExecutableLiteral) {
        Object literalValue = ((ExecutableLiteral) stmt).getLiteral();

      // Handle the case when the literal is null MVEL-312 
      if(literalValue == null){
        mv.visitInsn(ACONST_NULL);
        return null;
      }        
        
      Class type = literalValue == null ? desiredTarget : literalValue.getClass();

      assert debug("*** type:" + type + ";desired:" + desiredTarget);

      if (type == Integer.class && desiredTarget == int.class) {
        intPush(((ExecutableLiteral) stmt).getInteger32());
        type = int.class;
      }
      else if (desiredTarget != null && desiredTarget != type) {
        assert debug("*** Converting because desiredType(" + desiredTarget.getClass() + ") is not: " + type);


        if (!DataConversion.canConvert(type, desiredTarget)) {
          throw new CompileException("was expecting type: " + desiredTarget.getName()
              + "; but found type: " + type.getName(), expr, st);
        }
        writeOutLiteralWrapped(convert(literalValue, desiredTarget));
      }
      else {
        writeOutLiteralWrapped(literalValue);
      }

      return type;
    }
    else {
      literal = false;

      addSubstatement((ExecutableStatement) stmt);

      Class type;
      if (knownIngressType == null) {
        type = ((ExecutableStatement) stmt).getKnownEgressType();
      }
      else {
        type = knownIngressType;
      }

      if (desiredTarget != null && type != desiredTarget) {
        if (desiredTarget.isPrimitive()) {
          if (type == null) throw new OptimizationFailure("cannot optimize expression: " + new String(expr) +
              ": cannot determine ingress type for primitive output");

          checkcast(type);
          unwrapPrimitive(desiredTarget);
        }
      }

      return type;
    }
  }

  private void addPrintOut(String text) {
    mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
    mv.visitLdcInsn(text);
    mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
  }


  public Accessor optimizeCollection(ParserContext pCtx, Object o, Class type, char[] property, int start, int offset,
                                     Object ctx, Object thisRef, VariableResolverFactory factory) {
    this.expr = property;
    this.cursor = this.start = start;
    this.end = start + offset;
    this.length = offset;

    type = toNonPrimitiveArray(type);
    this.returnType = type;

    this.compiledInputs = new ArrayList<ExecutableStatement>();

    this.ctx = ctx;
    this.thisRef = thisRef;
    this.variableFactory = factory;
    this.pCtx = pCtx;

    _initJIT();

    literal = true;

    _getAccessor(o, type);

    _finishJIT();

    try {
      Accessor compiledAccessor = _initializeAccessor();

      if (property != null && length > start) {
        return new Union(pCtx, compiledAccessor, property, start, length);
      }
      else {
        return compiledAccessor;
      }

    }
    catch (Exception e) {
      throw new OptimizationFailure("could not optimize collection", e);
    }
  }

  private void checkcast(Class cls) {
    assert debug("CHECKCAST " + getInternalName(cls));
    mv.visitTypeInsn(CHECKCAST, getInternalName(cls));
  }

  private void intPush(int index) {
    if (index >= 0 && index < 6) {
      switch (index) {
        case 0:
          assert debug("ICONST_0");
          mv.visitInsn(ICONST_0);
          break;
        case 1:
          assert debug("ICONST_1");
          mv.visitInsn(ICONST_1);
          break;
        case 2:
          assert debug("ICONST_2");
          mv.visitInsn(ICONST_2);
          break;
        case 3:
          assert debug("ICONST_3");
          mv.visitInsn(ICONST_3);
          break;
        case 4:
          assert debug("ICONST_4");
          mv.visitInsn(ICONST_4);
          break;
        case 5:
          assert debug("ICONST_5");
          mv.visitInsn(ICONST_5);
          break;
      }
    }
    else if (index > -127 && index < 128) {
      assert debug("BIPUSH " + index);
      mv.visitIntInsn(BIPUSH, index);
    }
    else if (index > Short.MAX_VALUE) {
      assert debug("LDC " + index);
      mv.visitLdcInsn(index);
    }
    else {
      assert debug("SIPUSH " + index);
      mv.visitIntInsn(SIPUSH, index);
    }
  }

  public Accessor optimizeObjectCreation(ParserContext pCtx, char[] property, int start, int offset, Object ctx,
                                         Object thisRef, VariableResolverFactory factory) {
    _initJIT();

    compiledInputs = new ArrayList<ExecutableStatement>();
    this.start = cursor = start;
    this.end = start + offset;
    this.length = this.end - this.start;
    this.ctx = ctx;
    this.thisRef = thisRef;
    this.variableFactory = factory;
    this.pCtx = pCtx;

    String[] cnsRes = captureContructorAndResidual(property, start, offset);
    List<char[]> constructorParms = parseMethodOrConstructor(cnsRes[0].toCharArray());

    try {
      if (constructorParms != null) {
        for (char[] constructorParm : constructorParms) {
          compiledInputs.add((ExecutableStatement) subCompileExpression(constructorParm, pCtx));
        }

        Class cls = findClass(factory, new String(subset(property, 0, findFirst('(', start, length, property))), pCtx);

        assert debug("NEW " + getInternalName(cls));
        mv.visitTypeInsn(NEW, getInternalName(cls));
        assert debug("DUP");
        mv.visitInsn(DUP);

        Object[] parms = new Object[constructorParms.size()];

        int i = 0;
        for (ExecutableStatement es : compiledInputs) {
          parms[i++] = es.getValue(ctx, factory);
        }

        Constructor cns = getBestConstructorCandidate(parms, cls, pCtx.isStrongTyping());

        if (cns == null) {
          StringBuilder error = new StringBuilder();
          for (int x = 0; x < parms.length; x++) {
            error.append(parms[x].getClass().getName());
            if (x + 1 < parms.length) error.append(", ");
          }

          throw new CompileException("unable to find constructor: " + cls.getName()
              + "(" + error.toString() + ")", expr, st);
        }

        this.returnType = cns.getDeclaringClass();

        Class tg;
        for (i = 0; i < constructorParms.size(); i++) {
          assert debug("ALOAD 0");
          mv.visitVarInsn(ALOAD, 0);
          assert debug("GETFIELD p" + i);
          mv.visitFieldInsn(GETFIELD, className, "p" + i, "L" + NAMESPACE + "compiler/ExecutableStatement;");
          assert debug("ALOAD 2");
          mv.visitVarInsn(ALOAD, 2);
          assert debug("ALOAD 3");
          mv.visitVarInsn(ALOAD, 3);
          assert debug("INVOKEINTERFACE " + NAMESPACE + "compiler/ExecutableStatement.getValue");
          mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE
              + "compiler/ExecutableStatement", "getValue", "(Ljava/lang/Object;L" + NAMESPACE
              + "integration/VariableResolverFactory;)Ljava/lang/Object;");

          tg = cns.getParameterTypes()[i].isPrimitive()
              ? getWrapperClass(cns.getParameterTypes()[i]) : cns.getParameterTypes()[i];

          if (parms[i] != null && !parms[i].getClass().isAssignableFrom(cns.getParameterTypes()[i])) {
            ldcClassConstant(tg);

            assert debug("INVOKESTATIC " + NAMESPACE + "DataConversion.convert");
            mv.visitMethodInsn(INVOKESTATIC, "" + NAMESPACE + "DataConversion", "convert",
                "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");

            if (cns.getParameterTypes()[i].isPrimitive()) {
              unwrapPrimitive(cns.getParameterTypes()[i]);
            }
            else {
              assert debug("CHECKCAST " + getInternalName(tg));
              mv.visitTypeInsn(CHECKCAST, getInternalName(tg));
            }

          }
          else {
            assert debug("CHECKCAST " + getInternalName(cns.getParameterTypes()[i]));
            mv.visitTypeInsn(CHECKCAST, getInternalName(cns.getParameterTypes()[i]));
          }

        }

        assert debug("INVOKESPECIAL " + getInternalName(cls) + ".<init> : " + getConstructorDescriptor(cns));
        mv.visitMethodInsn(INVOKESPECIAL, getInternalName(cls), "<init>", getConstructorDescriptor(cns));

        _finishJIT();

        Accessor acc = _initializeAccessor();

        if (cnsRes.length > 1 && cnsRes[1] != null && !cnsRes[1].trim().equals("")) {
          return new Union(pCtx, acc, cnsRes[1].toCharArray(), 0, cnsRes[1].length());
        }

        return acc;
      }
      else {
        Class cls = findClass(factory, new String(property), pCtx);

        assert debug("NEW " + getInternalName(cls));
        mv.visitTypeInsn(NEW, getInternalName(cls));
        assert debug("DUP");
        mv.visitInsn(DUP);

        Constructor cns = cls.getConstructor(EMPTYCLS);

        assert debug("INVOKESPECIAL <init>");

        mv.visitMethodInsn(INVOKESPECIAL, getInternalName(cls), "<init>", getConstructorDescriptor(cns));

        _finishJIT();
        Accessor acc = _initializeAccessor();

        if (cnsRes.length > 1 && cnsRes[1] != null && !cnsRes[1].trim().equals("")) {
          return new Union(pCtx, acc, cnsRes[1].toCharArray(), 0, cnsRes[1].length());
        }

        return acc;
      }
    }
    catch (ClassNotFoundException e) {
      throw new CompileException("class or class reference not found: "
          + new String(property), property, st);
    }
    catch (Exception e) {
      throw new OptimizationFailure("could not optimize construtor: " + new String(property), e);
    }
  }

  public Class getEgressType() {
    return returnType;
  }

  private void dumpAdvancedDebugging() {
    if (buildLog == null) return;

    System.out.println("JIT Compiler Dump for: <<" + (expr == null ? null : new String(expr))
        + ">>\n-------------------------------\n");
    System.out.println(buildLog.toString());
    System.out.println("\n<END OF DUMP>\n");
    if (MVEL.isFileDebugging()) {
      try {
        FileWriter writer = ParseTools.getDebugFileWriter();
        writer.write(buildLog.toString());
        writer.flush();
        writer.close();
      }
      catch (IOException e) {
        //empty
      }
    }
  }

  private Object propHandlerByteCode(String property, Object ctx, Class handler) {
    PropertyHandler ph = getPropertyHandler(handler);
    if (ph instanceof ProducesBytecode) {
      assert debug("<<3rd-Party Code Generation>>");
      ((ProducesBytecode) ph).produceBytecodeGet(mv, property, variableFactory);
      return ph.getProperty(property, ctx, variableFactory);
    }
    else {
      throw new RuntimeException("unable to compileShared: custom accessor does not support producing bytecode: "
          + ph.getClass().getName());
    }
  }

  private void propHandlerByteCodePut(String property, Object ctx, Class handler, Object value) {
    PropertyHandler ph = getPropertyHandler(handler);
    if (ph instanceof ProducesBytecode) {
      assert debug("<<3rd-Party Code Generation>>");
      ((ProducesBytecode) ph).produceBytecodePut(mv, property, variableFactory);
      ph.setProperty(property, ctx, variableFactory, value);
    }
    else {
      throw new RuntimeException("unable to compileShared: custom accessor does not support producing bytecode: "
          + ph.getClass().getName());
    }
  }

  private void writeOutNullHandler(Member member, int type) {

    assert debug("DUP");
    mv.visitInsn(DUP);

    Label j = new Label();

    assert debug("IFNONNULL : jump");
    mv.visitJumpInsn(IFNONNULL, j);

    assert debug("POP");
    mv.visitInsn(POP);

    assert debug("ALOAD 0");
    mv.visitVarInsn(ALOAD, 0);

    if (type == 0) {
      this.propNull = true;

      assert debug("GETFIELD 'nullPropertyHandler'");
      mv.visitFieldInsn(GETFIELD, className, "nullPropertyHandler", "L" + NAMESPACE + "integration/PropertyHandler;");
    }
    else {
      this.methNull = true;

      assert debug("GETFIELD 'nullMethodHandler'");
      mv.visitFieldInsn(GETFIELD, className, "nullMethodHandler", "L" + NAMESPACE + "integration/PropertyHandler;");
    }