Search in sources :

Example 1 with ArrayLength

use of org.mvel2.optimizers.impl.refl.nodes.ArrayLength in project mvel by mikebrock.

the class ASMAccessorOptimizer method writeFunctionPointerStub.

private void writeFunctionPointerStub(Class c, Method m) {
    ldcClassConstant(c);
    mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethods", "()[Ljava/lang/reflect/Method;");
    mv.visitVarInsn(ASTORE, 7);
    mv.visitInsn(ICONST_0);
    mv.visitVarInsn(ISTORE, 5);
    mv.visitVarInsn(ALOAD, 7);
    mv.visitInsn(ARRAYLENGTH);
    mv.visitVarInsn(ISTORE, 6);
    Label l1 = new Label();
    mv.visitJumpInsn(GOTO, l1);
    Label l2 = new Label();
    mv.visitLabel(l2);
    mv.visitVarInsn(ALOAD, 7);
    mv.visitVarInsn(ILOAD, 5);
    mv.visitInsn(AALOAD);
    mv.visitVarInsn(ASTORE, 4);
    Label l3 = new Label();
    mv.visitLabel(l3);
    mv.visitLdcInsn(m.getName());
    mv.visitVarInsn(ALOAD, 4);
    mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "getName", "()Ljava/lang/String;");
    mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
    Label l4 = new Label();
    mv.visitJumpInsn(IFEQ, l4);
    Label l5 = new Label();
    mv.visitLabel(l5);
    mv.visitVarInsn(ALOAD, 4);
    mv.visitInsn(ARETURN);
    mv.visitLabel(l4);
    mv.visitIincInsn(5, 1);
    mv.visitLabel(l1);
    mv.visitVarInsn(ILOAD, 5);
    mv.visitVarInsn(ILOAD, 6);
    mv.visitJumpInsn(IF_ICMPLT, l2);
    Label l6 = new Label();
    mv.visitLabel(l6);
    mv.visitInsn(ACONST_NULL);
    mv.visitInsn(ARETURN);
// deferFinish = true;
}
Also used : Label(org.mvel2.asm.Label)

Example 2 with ArrayLength

use of org.mvel2.optimizers.impl.refl.nodes.ArrayLength in project mvel by mvel.

the class ASMAccessorOptimizer method getBeanProperty.

private Object getBeanProperty(Object ctx, String property) throws IllegalAccessException, InvocationTargetException {
    assert debug("\n  **  ENTER -> {bean: " + property + "; ctx=" + ctx + "}");
    if ((pCtx == null ? currType : pCtx.getVarOrInputTypeOrNull(property)) == Object.class && !pCtx.isStrongTyping()) {
        currType = null;
    }
    if (returnType != null && returnType.isPrimitive()) {
        // noinspection unchecked
        wrapPrimitive(returnType);
    }
    boolean classRef = false;
    Class<?> cls;
    if (ctx instanceof Class) {
        if (MVEL.COMPILER_OPT_SUPPORT_JAVA_STYLE_CLASS_LITERALS && "class".equals(property)) {
            ldcClassConstant((Class<?>) ctx);
            return ctx;
        }
        cls = (Class<?>) ctx;
        classRef = true;
    } else if (ctx != null) {
        cls = ctx.getClass();
    } else {
        cls = null;
    }
    if (hasPropertyHandler(cls)) {
        PropertyHandler prop = getPropertyHandler(cls);
        if (prop instanceof ProducesBytecode) {
            ((ProducesBytecode) prop).produceBytecodeGet(mv, property, variableFactory);
            return prop.getProperty(property, ctx, variableFactory);
        } else {
            throw new RuntimeException("unable to compileShared: custom accessor does not support producing bytecode: " + prop.getClass().getName());
        }
    }
    Member member = cls != null ? getFieldOrAccessor(cls, property) : null;
    if (member != null && classRef && (member.getModifiers() & Modifier.STATIC) == 0) {
        member = null;
    }
    if (member != null && hasGetListeners()) {
        mv.visitVarInsn(ALOAD, 1);
        mv.visitLdcInsn(member.getName());
        mv.visitVarInsn(ALOAD, 3);
        mv.visitMethodInsn(INVOKESTATIC, NAMESPACE + "integration/GlobalListenerFactory", "notifyGetListeners", "(Ljava/lang/Object;Ljava/lang/String;L" + NAMESPACE + "integration/VariableResolverFactory;)V");
        notifyGetListeners(ctx, member.getName(), variableFactory);
    }
    if (first) {
        if ("this".equals(property)) {
            assert debug("ALOAD 2");
            mv.visitVarInsn(ALOAD, 2);
            return thisRef;
        } else if (variableFactory != null && variableFactory.isResolveable(property)) {
            if (variableFactory.isIndexedFactory() && variableFactory.isTarget(property)) {
                int idx;
                try {
                    loadVariableByIndex(idx = variableFactory.variableIndexOf(property));
                } catch (Exception e) {
                    throw new OptimizationFailure(property);
                }
                return variableFactory.getIndexedVariableResolver(idx).getValue();
            } else {
                try {
                    loadVariableByName(property);
                } catch (Exception e) {
                    throw new OptimizationFailure("critical error in JIT", e);
                }
                return variableFactory.getVariableResolver(property).getValue();
            }
        } else {
            assert debug("ALOAD 1");
            mv.visitVarInsn(ALOAD, 1);
        }
    }
    if (member instanceof Field) {
        return optimizeFieldMethodProperty(ctx, property, cls, member);
    } else if (member != null) {
        Object o;
        if (first) {
            assert debug("ALOAD 1 (B)");
            mv.visitVarInsn(ALOAD, 1);
        }
        try {
            o = ((Method) member).invoke(ctx, EMPTYARG);
            if (returnType != member.getDeclaringClass()) {
                assert debug("CHECKCAST " + getInternalName(member.getDeclaringClass()));
                mv.visitTypeInsn(CHECKCAST, getInternalName(member.getDeclaringClass()));
            }
            returnType = ((Method) member).getReturnType();
            if (member.getDeclaringClass().isInterface()) {
                assert debug("INVOKEINTERFACE " + member.getName() + ":" + returnType);
                mv.visitMethodInsn(INVOKEINTERFACE, getInternalName(member.getDeclaringClass()), member.getName(), getMethodDescriptor((Method) member));
            } else {
                assert debug("INVOKEVIRTUAL " + member.getName() + ":" + returnType);
                mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(member.getDeclaringClass()), member.getName(), getMethodDescriptor((Method) member));
            }
        } catch (IllegalAccessException e) {
            Method iFaceMeth = determineActualTargetMethod((Method) member);
            if (iFaceMeth == null)
                throw new PropertyAccessException("could not access field: " + cls.getName() + "." + property, expr, st, e, pCtx);
            assert debug("CHECKCAST " + getInternalName(iFaceMeth.getDeclaringClass()));
            mv.visitTypeInsn(CHECKCAST, getInternalName(iFaceMeth.getDeclaringClass()));
            returnType = iFaceMeth.getReturnType();
            assert debug("INVOKEINTERFACE " + member.getName() + ":" + returnType);
            mv.visitMethodInsn(INVOKEINTERFACE, getInternalName(iFaceMeth.getDeclaringClass()), member.getName(), getMethodDescriptor((Method) member));
            o = iFaceMeth.invoke(ctx, EMPTYARG);
        } catch (IllegalArgumentException e) {
            if (member.getDeclaringClass().equals(ctx)) {
                try {
                    Class c = Class.forName(member.getDeclaringClass().getName() + "$" + property);
                    throw new CompileException("name collision between innerclass: " + c.getCanonicalName() + "; and bean accessor: " + property + " (" + member.toString() + ")", expr, tkStart);
                } catch (ClassNotFoundException e2) {
                // fallthru
                }
            }
            throw e;
        }
        if (hasNullPropertyHandler()) {
            if (o == null)
                o = getNullPropertyHandler().getProperty(member.getName(), ctx, variableFactory);
            writeOutNullHandler(member, 0);
        }
        currType = toNonPrimitiveType(returnType);
        return o;
    } else if (ctx instanceof Map && (((Map) ctx).containsKey(property) || nullSafe)) {
        assert debug("CHECKCAST java/util/Map");
        mv.visitTypeInsn(CHECKCAST, "java/util/Map");
        assert debug("LDC: \"" + property + "\"");
        mv.visitLdcInsn(property);
        assert debug("INVOKEINTERFACE: get");
        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
        return ((Map) ctx).get(property);
    } else if (first && "this".equals(property)) {
        assert debug("ALOAD 2");
        // load the thisRef value.
        mv.visitVarInsn(ALOAD, 2);
        return this.thisRef;
    } else if ("length".equals(property) && ctx.getClass().isArray()) {
        anyArrayCheck(ctx.getClass());
        assert debug("ARRAYLENGTH");
        mv.visitInsn(ARRAYLENGTH);
        wrapPrimitive(int.class);
        return getLength(ctx);
    } else if (LITERALS.containsKey(property)) {
        Object lit = LITERALS.get(property);
        if (lit instanceof Class) {
            ldcClassConstant((Class) lit);
        }
        return lit;
    } else {
        Object ts = tryStaticAccess();
        if (ts != null) {
            if (ts instanceof Class) {
                ldcClassConstant((Class) ts);
                return ts;
            } else if (ts instanceof Method) {
                writeFunctionPointerStub(((Method) ts).getDeclaringClass(), (Method) ts);
                return ts;
            } else {
                Field f = (Field) ts;
                return optimizeFieldMethodProperty(ctx, property, cls, f);
            }
        } else if (ctx instanceof Class) {
            /**
             * This is our ugly support for function pointers.  This works but needs to be re-thought out at some
             * point.
             */
            Class c = (Class) ctx;
            for (Method m : c.getMethods()) {
                if (property.equals(m.getName())) {
                    if (pCtx != null && pCtx.getParserConfiguration() != null ? pCtx.getParserConfiguration().isAllowNakedMethCall() : MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL) {
                        assert debug("POP");
                        mv.visitInsn(POP);
                        assert debug("INVOKESTATIC " + m.getName());
                        mv.visitMethodInsn(INVOKESTATIC, getInternalName(m.getDeclaringClass()), m.getName(), getMethodDescriptor(m));
                        returnType = m.getReturnType();
                        return m.invoke(null, EMPTY_OBJ_ARR);
                    } else {
                        writeFunctionPointerStub(c, m);
                        return m;
                    }
                }
            }
            try {
                Class subClass = findClass(variableFactory, c.getName() + "$" + property, pCtx);
                ldcClassConstant(subClass);
                return subClass;
            } catch (ClassNotFoundException cnfe) {
            // fall through.
            }
        } else if (pCtx != null && pCtx.getParserConfiguration() != null ? pCtx.getParserConfiguration().isAllowNakedMethCall() : MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL) {
            return getMethod(ctx, property);
        }
        if (ctx == null) {
            throw new PropertyAccessException("unresolvable property or identifier: " + property, expr, st, pCtx);
        } else {
            throw new PropertyAccessException("could not access: " + property + "; in class: " + ctx.getClass().getName(), expr, st, pCtx);
        }
    }
}
Also used : OptimizationFailure(org.mvel2.OptimizationFailure) PropertyAccessException(org.mvel2.PropertyAccessException) ParseTools.determineActualTargetMethod(org.mvel2.util.ParseTools.determineActualTargetMethod) Method(java.lang.reflect.Method) InvocationTargetException(java.lang.reflect.InvocationTargetException) PropertyAccessException(org.mvel2.PropertyAccessException) IOException(java.io.IOException) CompileException(org.mvel2.CompileException) Field(java.lang.reflect.Field) PropertyHandlerFactory.hasNullPropertyHandler(org.mvel2.integration.PropertyHandlerFactory.hasNullPropertyHandler) PropertyHandlerFactory.getNullPropertyHandler(org.mvel2.integration.PropertyHandlerFactory.getNullPropertyHandler) PropertyHandlerFactory.hasPropertyHandler(org.mvel2.integration.PropertyHandlerFactory.hasPropertyHandler) PropertyHandlerFactory.getPropertyHandler(org.mvel2.integration.PropertyHandlerFactory.getPropertyHandler) PropertyHandler(org.mvel2.integration.PropertyHandler) CompileException(org.mvel2.CompileException) ParseTools.findClass(org.mvel2.util.ParseTools.findClass) Member(java.lang.reflect.Member) Map(java.util.Map)

Example 3 with ArrayLength

use of org.mvel2.optimizers.impl.refl.nodes.ArrayLength in project mvel by mvel.

the class ASMAccessorOptimizer method getMethod.

@SuppressWarnings({ "unchecked" })
private Object getMethod(Object ctx, String name) throws IllegalAccessException, InvocationTargetException {
    assert debug("\n  **  {method: " + name + "}");
    int st = cursor;
    String tk = cursor != end && expr[cursor] == '(' && ((cursor = balancedCapture(expr, cursor, '(')) - st) > 1 ? new String(expr, st + 1, cursor - st - 1) : "";
    cursor++;
    Object[] preConvArgs;
    Object[] args;
    Class[] argTypes;
    ExecutableStatement[] es;
    List<char[]> subtokens;
    if (tk.length() == 0) {
        args = preConvArgs = ParseTools.EMPTY_OBJ_ARR;
        argTypes = ParseTools.EMPTY_CLS_ARR;
        es = null;
        subtokens = null;
    } else {
        subtokens = parseParameterList(tk.toCharArray(), 0, -1);
        es = new ExecutableStatement[subtokens.size()];
        args = new Object[subtokens.size()];
        argTypes = new Class[subtokens.size()];
        preConvArgs = new Object[es.length];
        for (int i = 0; i < subtokens.size(); i++) {
            assert debug("subtoken[" + i + "] { " + new String(subtokens.get(i)) + " }");
            preConvArgs[i] = args[i] = (es[i] = (ExecutableStatement) subCompileExpression(subtokens.get(i), pCtx)).getValue(this.thisRef, this.thisRef, variableFactory);
            if (es[i].isExplicitCast())
                argTypes[i] = es[i].getKnownEgressType();
        }
        if (pCtx.isStrictTypeEnforcement()) {
            for (int i = 0; i < args.length; i++) {
                argTypes[i] = es[i].getKnownEgressType();
                if (es[i] instanceof ExecutableLiteral && ((ExecutableLiteral) es[i]).getLiteral() == null) {
                    argTypes[i] = NullType.class;
                }
            }
        } else {
            for (int i = 0; i < args.length; i++) {
                if (argTypes[i] != null)
                    continue;
                if (es[i].getKnownEgressType() == Object.class) {
                    argTypes[i] = args[i] == null ? null : args[i].getClass();
                } else {
                    argTypes[i] = es[i].getKnownEgressType();
                }
            }
        }
    }
    if (first && variableFactory != null && variableFactory.isResolveable(name)) {
        Object ptr = variableFactory.getVariableResolver(name).getValue();
        if (ptr instanceof Method) {
            ctx = ((Method) ptr).getDeclaringClass();
            name = ((Method) ptr).getName();
        } else if (ptr instanceof MethodStub) {
            ctx = ((MethodStub) ptr).getClassReference();
            name = ((MethodStub) ptr).getMethodName();
        } else if (ptr instanceof FunctionInstance) {
            if (es != null && es.length != 0) {
                compiledInputs.addAll(Arrays.asList(es));
                intPush(es.length);
                assert debug("ANEWARRAY [" + es.length + "]");
                mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
                assert debug("ASTORE 4");
                mv.visitVarInsn(ASTORE, 4);
                for (int i = 0; i < es.length; i++) {
                    assert debug("ALOAD 4");
                    mv.visitVarInsn(ALOAD, 4);
                    intPush(i);
                    loadField(i);
                    assert debug("ALOAD 1");
                    mv.visitVarInsn(ALOAD, 1);
                    assert debug("ALOAD 3");
                    mv.visitIntInsn(ALOAD, 3);
                    assert debug("INVOKEINTERFACE ExecutableStatement.getValue");
                    mv.visitMethodInsn(INVOKEINTERFACE, NAMESPACE + "compiler/ExecutableStatement", "getValue", "(Ljava/lang/Object;L" + NAMESPACE + "integration/VariableResolverFactory;)Ljava/lang/Object;");
                    assert debug("AASTORE");
                    mv.visitInsn(AASTORE);
                }
            } else {
                assert debug("ACONST_NULL");
                mv.visitInsn(ACONST_NULL);
                assert debug("CHECKCAST java/lang/Object");
                mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
                assert debug("ASTORE 4");
                mv.visitVarInsn(ASTORE, 4);
            }
            if (variableFactory.isIndexedFactory() && variableFactory.isTarget(name)) {
                loadVariableByIndex(variableFactory.variableIndexOf(name));
            } else {
                loadVariableByName(name);
            }
            checkcast(FunctionInstance.class);
            assert debug("ALOAD 1");
            mv.visitVarInsn(ALOAD, 1);
            assert debug("ALOAD 2");
            mv.visitVarInsn(ALOAD, 2);
            assert debug("ALOAD 3");
            mv.visitVarInsn(ALOAD, 3);
            assert debug("ALOAD 4");
            mv.visitVarInsn(ALOAD, 4);
            assert debug("INVOKEVIRTUAL Function.call");
            mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(FunctionInstance.class), "call", "(Ljava/lang/Object;Ljava/lang/Object;L" + NAMESPACE + "integration/VariableResolverFactory;[Ljava/lang/Object;)Ljava/lang/Object;");
            return ((FunctionInstance) ptr).call(ctx, thisRef, variableFactory, args);
        } else {
            throw new OptimizationFailure("attempt to optimize a method call for a reference that does not point to a method: " + name + " (reference is type: " + (ctx != null ? ctx.getClass().getName() : null) + ")");
        }
        first = false;
    } else if (returnType != null && returnType.isPrimitive()) {
        // noinspection unchecked
        wrapPrimitive(returnType);
    }
    /**
     * If the target object is an instance of java.lang.Class itself then do not
     * adjust the Class scope target.
     */
    boolean classTarget = false;
    Class<?> cls = currType != null ? currType : ((classTarget = ctx instanceof Class) ? (Class<?>) ctx : ctx.getClass());
    currType = null;
    Method m;
    Class[] parameterTypes = null;
    /**
     * Try to find an instance method from the class target.
     */
    if ((m = getBestCandidate(argTypes, name, cls, cls.getMethods(), false, classTarget)) != null) {
        parameterTypes = m.getParameterTypes();
    }
    if (m == null && classTarget) {
        /**
         * If we didn't find anything, maybe we're looking for the actual java.lang.Class methods.
         */
        if ((m = getBestCandidate(argTypes, name, cls, Class.class.getMethods(), false)) != null) {
            parameterTypes = m.getParameterTypes();
        }
    }
    // If we didn't find anything and the declared class is different from the actual one try also with the actual one
    if (m == null && cls != ctx.getClass() && !(ctx instanceof Class)) {
        cls = ctx.getClass();
        if ((m = getBestCandidate(argTypes, name, cls, cls.getMethods(), false, classTarget)) != null) {
            parameterTypes = m.getParameterTypes();
        }
    }
    if (es != null && m != null && m.isVarArgs() && (es.length != parameterTypes.length || !(es[es.length - 1] instanceof ExecutableAccessor))) {
        // normalize ExecutableStatement for varargs
        ExecutableStatement[] varArgEs = new ExecutableStatement[parameterTypes.length];
        int varArgStart = parameterTypes.length - 1;
        for (int i = 0; i < varArgStart; i++) varArgEs[i] = es[i];
        String varargsTypeName = parameterTypes[parameterTypes.length - 1].getComponentType().getName();
        String varArgExpr;
        if ("null".equals(tk)) {
            // if null is the token no need for wrapping
            varArgExpr = tk;
        } else {
            StringBuilder sb = new StringBuilder("new ").append(varargsTypeName).append("[] {");
            for (int i = varArgStart; i < subtokens.size(); i++) {
                sb.append(subtokens.get(i));
                if (i < subtokens.size() - 1)
                    sb.append(",");
            }
            varArgExpr = sb.append("}").toString();
        }
        char[] token = varArgExpr.toCharArray();
        varArgEs[varArgStart] = ((ExecutableStatement) subCompileExpression(token, pCtx));
        es = varArgEs;
        if (preConvArgs.length == parameterTypes.length - 1) {
            // empty vararg
            Object[] preConvArgsForVarArg = new Object[parameterTypes.length];
            for (int i = 0; i < preConvArgs.length; i++) preConvArgsForVarArg[i] = preConvArgs[i];
            preConvArgsForVarArg[parameterTypes.length - 1] = Array.newInstance(parameterTypes[parameterTypes.length - 1].getComponentType(), 0);
            preConvArgs = preConvArgsForVarArg;
        }
    }
    int inputsOffset = compiledInputs.size();
    if (es != null) {
        for (ExecutableStatement e : es) {
            if (e instanceof ExecutableLiteral) {
                continue;
            }
            compiledInputs.add(e);
        }
    }
    if (first) {
        assert debug("ALOAD 1 (D) ");
        mv.visitVarInsn(ALOAD, 1);
    }
    if (m == null) {
        StringAppender errorBuild = new StringAppender();
        if (parameterTypes != null) {
            for (int i = 0; i < args.length; i++) {
                errorBuild.append(parameterTypes[i] != null ? parameterTypes[i].getClass().getName() : null);
                if (i < args.length - 1)
                    errorBuild.append(", ");
            }
        }
        if ("size".equals(name) && args.length == 0 && cls.isArray()) {
            anyArrayCheck(cls);
            assert debug("ARRAYLENGTH");
            mv.visitInsn(ARRAYLENGTH);
            wrapPrimitive(int.class);
            return getLength(ctx);
        }
        throw new CompileException("unable to resolve method: " + cls.getName() + "." + name + "(" + errorBuild.toString() + ") [arglength=" + args.length + "]", expr, st);
    } else {
        m = getWidenedTarget(m);
        if (es != null) {
            ExecutableStatement cExpr;
            for (int i = 0; i < es.length; i++) {
                if ((cExpr = es[i]).getKnownIngressType() == null) {
                    cExpr.setKnownIngressType(parameterTypes[i]);
                    cExpr.computeTypeConversionRule();
                }
                if (!cExpr.isConvertableIngressEgress() && i < args.length) {
                    args[i] = convert(args[i], paramTypeVarArgsSafe(parameterTypes, i, m.isVarArgs()));
                }
            }
        } else {
            /**
             * Coerce any types if required.
             */
            for (int i = 0; i < args.length; i++) {
                args[i] = convert(args[i], paramTypeVarArgsSafe(parameterTypes, i, m.isVarArgs()));
            }
        }
        Class<?> declaringClass = m.getDeclaringClass();
        if (m.getParameterTypes().length == 0) {
            if ((m.getModifiers() & STATIC) != 0) {
                assert debug("INVOKESTATIC " + m.getName());
                mv.visitMethodInsn(INVOKESTATIC, getInternalName(declaringClass), m.getName(), getMethodDescriptor(m));
            } else {
                assert debug("CHECKCAST " + getInternalName(declaringClass));
                mv.visitTypeInsn(CHECKCAST, getInternalName(declaringClass));
                if (declaringClass.isInterface()) {
                    assert debug("INVOKEINTERFACE " + m.getName());
                    mv.visitMethodInsn(INVOKEINTERFACE, getInternalName(declaringClass), m.getName(), getMethodDescriptor(m));
                } else {
                    assert debug("INVOKEVIRTUAL " + m.getName());
                    mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(declaringClass), m.getName(), getMethodDescriptor(m));
                }
            }
            returnType = m.getReturnType();
            stacksize++;
        } else {
            if ((m.getModifiers() & STATIC) == 0) {
                assert debug("CHECKCAST " + getInternalName(declaringClass));
                mv.visitTypeInsn(CHECKCAST, getInternalName(declaringClass));
            }
            for (int i = 0; es != null && i < es.length; i++) {
                if (es[i] instanceof ExecutableLiteral) {
                    ExecutableLiteral literal = (ExecutableLiteral) es[i];
                    if (literal.getLiteral() == null) {
                        assert debug("ICONST_NULL");
                        mv.visitInsn(ACONST_NULL);
                        continue;
                    } else if (parameterTypes[i] == int.class && literal.intOptimized()) {
                        intPush(literal.getInteger32());
                        continue;
                    } else if (parameterTypes[i] == int.class && preConvArgs[i] instanceof Integer) {
                        intPush((Integer) preConvArgs[i]);
                        continue;
                    } else if (parameterTypes[i] == boolean.class) {
                        boolean bool = DataConversion.convert(literal.getLiteral(), Boolean.class);
                        assert debug(bool ? "ICONST_1" : "ICONST_0");
                        mv.visitInsn(bool ? ICONST_1 : ICONST_0);
                        continue;
                    } else {
                        Object lit = literal.getLiteral();
                        if (parameterTypes[i] == Object.class) {
                            if (isPrimitiveWrapper(lit.getClass())) {
                                if (lit.getClass() == Integer.class) {
                                    intPush((Integer) lit);
                                } else {
                                    assert debug("LDC " + lit);
                                    mv.visitLdcInsn(lit);
                                }
                                wrapPrimitive(lit.getClass());
                            } else if (lit instanceof String) {
                                mv.visitLdcInsn(lit);
                                checkcast(Object.class);
                            }
                            continue;
                        } else if (canConvert(parameterTypes[i], lit.getClass())) {
                            Object c = convert(lit, parameterTypes[i]);
                            if (c instanceof Class) {
                                ldcClassConstant((Class) c);
                            } else {
                                assert debug("LDC " + lit + " (" + lit.getClass().getName() + ")");
                                mv.visitLdcInsn(c);
                                if (isPrimitiveWrapper(parameterTypes[i])) {
                                    wrapPrimitive(lit.getClass());
                                }
                            }
                            continue;
                        } else {
                            throw new OptimizationNotSupported();
                        }
                    }
                }
                assert debug("ALOAD 0");
                mv.visitVarInsn(ALOAD, 0);
                assert debug("GETFIELD p" + inputsOffset);
                mv.visitFieldInsn(GETFIELD, className, "p" + inputsOffset, "L" + NAMESPACE + "compiler/ExecutableStatement;");
                inputsOffset++;
                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;");
                if (parameterTypes[i].isPrimitive()) {
                    if (preConvArgs[i] == null || (parameterTypes[i] != String.class && !parameterTypes[i].isAssignableFrom(preConvArgs[i].getClass()))) {
                        ldcClassConstant(getWrapperClass(parameterTypes[i]));
                        assert debug("INVOKESTATIC DataConversion.convert");
                        mv.visitMethodInsn(INVOKESTATIC, NAMESPACE + "DataConversion", "convert", "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
                    }
                    unwrapPrimitive(parameterTypes[i]);
                } else if (preConvArgs[i] == null || (parameterTypes[i] != String.class && !parameterTypes[i].isAssignableFrom(preConvArgs[i].getClass()))) {
                    ldcClassConstant(parameterTypes[i]);
                    assert debug("INVOKESTATIC DataConversion.convert");
                    mv.visitMethodInsn(INVOKESTATIC, NAMESPACE + "DataConversion", "convert", "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
                    assert debug("CHECKCAST " + getInternalName(parameterTypes[i]));
                    mv.visitTypeInsn(CHECKCAST, getInternalName(parameterTypes[i]));
                } else if (parameterTypes[i] == String.class) {
                    assert debug("<<<DYNAMIC TYPE OPTIMIZATION STRING>>");
                    mv.visitVarInsn(ASTORE, 4);
                    Label jmp = new Label();
                    mv.visitVarInsn(ALOAD, 4);
                    mv.visitJumpInsn(IFNONNULL, jmp);
                    mv.visitInsn(ACONST_NULL);
                    Label jmp2 = new Label();
                    mv.visitJumpInsn(GOTO, jmp2);
                    mv.visitLabel(jmp);
                    mv.visitVarInsn(ALOAD, 4);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;");
                    mv.visitLabel(jmp2);
                } else {
                    assert debug("<<<DYNAMIC TYPING BYPASS>>>");
                    assert debug("<<<OPT. JUSTIFICATION " + parameterTypes[i] + "=" + preConvArgs[i].getClass() + ">>>");
                    assert debug("CHECKCAST " + getInternalName(parameterTypes[i]));
                    mv.visitTypeInsn(CHECKCAST, getInternalName(parameterTypes[i]));
                }
            }
            if (m.isVarArgs() && (es == null || es.length == (parameterTypes.length - 1))) {
                // The last parameter is a vararg and there is no value, create an empty array array
                createArray(getBaseComponentType(parameterTypes[parameterTypes.length - 1]), 0);
            }
            if ((m.getModifiers() & STATIC) != 0) {
                assert debug("INVOKESTATIC: " + m.getName());
                mv.visitMethodInsn(INVOKESTATIC, getInternalName(declaringClass), m.getName(), getMethodDescriptor(m));
            } else {
                if (declaringClass.isInterface()) {
                    assert debug("INVOKEINTERFACE: " + getInternalName(declaringClass) + "." + m.getName());
                    mv.visitMethodInsn(INVOKEINTERFACE, getInternalName(declaringClass), m.getName(), getMethodDescriptor(m));
                } else {
                    assert debug("INVOKEVIRTUAL: " + getInternalName(declaringClass) + "." + m.getName());
                    mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(declaringClass), m.getName(), getMethodDescriptor(m));
                }
            }
            returnType = m.getReturnType();
            stacksize++;
        }
        Object o = m.invoke(ctx, normalizeArgsForVarArgs(parameterTypes, args, m.isVarArgs()));
        if (hasNullMethodHandler()) {
            writeOutNullHandler(m, 1);
            if (o == null)
                o = getNullMethodHandler().getProperty(m.getName(), ctx, variableFactory);
        }
        currType = toNonPrimitiveType(m.getReturnType());
        return o;
    }
}
Also used : OptimizationFailure(org.mvel2.OptimizationFailure) ExecutableAccessor(org.mvel2.compiler.ExecutableAccessor) Label(org.mvel2.asm.Label) ExecutableLiteral(org.mvel2.compiler.ExecutableLiteral) StringAppender(org.mvel2.util.StringAppender) CompileException(org.mvel2.CompileException) OptimizationNotSupported(org.mvel2.optimizers.OptimizationNotSupported) ExecutableStatement(org.mvel2.compiler.ExecutableStatement) ParseTools.determineActualTargetMethod(org.mvel2.util.ParseTools.determineActualTargetMethod) Method(java.lang.reflect.Method) FunctionInstance(org.mvel2.ast.FunctionInstance) MethodStub(org.mvel2.util.MethodStub) ParseTools.findClass(org.mvel2.util.ParseTools.findClass)

Example 4 with ArrayLength

use of org.mvel2.optimizers.impl.refl.nodes.ArrayLength in project drools by kiegroup.

the class ConditionAnalyzer method analyzeAccessorInvocation.

private Invocation analyzeAccessorInvocation(AccessorNode accessorNode, ASTNode containingNode, Invocation formerInvocation, Class<?> variableType) {
    if (accessorNode instanceof GetterAccessor) {
        return new MethodInvocation(((GetterAccessor) accessorNode).getMethod(), variableType == null ? conditionClass : variableType.getName());
    }
    if (accessorNode instanceof MethodAccessor) {
        MethodAccessor methodAccessor = (MethodAccessor) accessorNode;
        Method method = methodAccessor.getMethod();
        MethodInvocation invocation = new MethodInvocation(method);
        boolean isVarArgs = method.isVarArgs();
        readInvocationParams(invocation, methodAccessor.getParms(), methodAccessor.getParameterTypes(), isVarArgs);
        return invocation;
    }
    if (accessorNode instanceof ConstructorAccessor) {
        ConstructorAccessor constructorAccessor = (ConstructorAccessor) accessorNode;
        Constructor constructor = constructorAccessor.getConstructor();
        ConstructorInvocation invocation = new ConstructorInvocation(constructor);
        readInvocationParams(invocation, constructorAccessor.getParameters(), constructorAccessor.getParameterTypes(), constructor.isVarArgs());
        return invocation;
    }
    if (accessorNode instanceof ArrayAccessor) {
        ArrayAccessor arrayAccessor = (ArrayAccessor) accessorNode;
        return new ArrayAccessInvocation(formerInvocation != null ? formerInvocation.getReturnType() : Object[].class, new FixedExpression(int.class, arrayAccessor.getIndex()));
    }
    if (accessorNode instanceof ArrayAccessorNest) {
        ArrayAccessorNest arrayAccessorNest = (ArrayAccessorNest) accessorNode;
        ExecutableAccessor index = (ExecutableAccessor) arrayAccessorNest.getIndex();
        return new ArrayAccessInvocation(formerInvocation != null ? formerInvocation.getReturnType() : Object[].class, analyzeNode(index.getNode()));
    }
    if (accessorNode instanceof ArrayLength) {
        return new ArrayLengthInvocation();
    }
    if (accessorNode instanceof ListAccessor) {
        Class<?> listType = getListType(formerInvocation);
        ListAccessor listAccessor = (ListAccessor) accessorNode;
        return new ListAccessInvocation(listType, new FixedExpression(int.class, listAccessor.getIndex()));
    }
    if (accessorNode instanceof ListAccessorNest) {
        Class<?> listType = getListType(formerInvocation);
        ListAccessorNest listAccessorNest = (ListAccessorNest) accessorNode;
        ExecutableAccessor index = (ExecutableAccessor) listAccessorNest.getIndex();
        return new ListAccessInvocation(listType, analyzeNode(index.getNode()));
    }
    if (accessorNode instanceof MapAccessor) {
        MapAccessor mapAccessor = (MapAccessor) accessorNode;
        return new MapAccessInvocation(Object.class, Object.class, new FixedExpression(Object.class, mapAccessor.getProperty()));
    }
    if (accessorNode instanceof MapAccessorNest) {
        Class<?> keyType = Object.class;
        Class<?> valueType = Object.class;
        Type[] generics = getGenerics(formerInvocation);
        if (generics != null && generics.length == 2 && generics[0] instanceof Class) {
            keyType = (Class<?>) generics[0];
            if (generics[1] instanceof Class)
                valueType = (Class<?>) generics[1];
        }
        MapAccessorNest mapAccessor = (MapAccessorNest) accessorNode;
        ExecutableStatement statement = mapAccessor.getProperty();
        if (statement instanceof ExecutableLiteral) {
            return new MapAccessInvocation(keyType, valueType, new FixedExpression(keyType, ((ExecutableLiteral) statement).getLiteral()));
        } else {
            return new MapAccessInvocation(keyType, valueType, analyzeNode(((ExecutableAccessor) statement).getNode()));
        }
    }
    if (accessorNode instanceof FieldAccessor) {
        return new FieldAccessInvocation(((FieldAccessor) accessorNode).getField());
    }
    if (accessorNode instanceof StaticVarAccessor) {
        Field field = ((StaticVarAccessor) accessorNode).getField();
        return new FieldAccessInvocation(field);
    }
    if (accessorNode instanceof ThisValueAccessor) {
        return new ThisInvocation(accessorNode.getNextNode() == null ? containingNode.getEgressType() : Object.class);
    }
    throw new RuntimeException("Unknown AccessorNode type: " + accessorNode.getClass().getName());
}
Also used : ArrayAccessorNest(org.mvel2.optimizers.impl.refl.nodes.ArrayAccessorNest) ExecutableAccessor(org.mvel2.compiler.ExecutableAccessor) FieldAccessor(org.mvel2.optimizers.impl.refl.nodes.FieldAccessor) ListAccessor(org.mvel2.optimizers.impl.refl.nodes.ListAccessor) Field(java.lang.reflect.Field) ThisValueAccessor(org.mvel2.optimizers.impl.refl.nodes.ThisValueAccessor) ExecutableLiteral(org.mvel2.compiler.ExecutableLiteral) MapAccessor(org.mvel2.optimizers.impl.refl.nodes.MapAccessor) ExecutableStatement(org.mvel2.compiler.ExecutableStatement) GetterAccessor(org.mvel2.optimizers.impl.refl.nodes.GetterAccessor) MethodAccessor(org.mvel2.optimizers.impl.refl.nodes.MethodAccessor) Constructor(java.lang.reflect.Constructor) ArrayLength(org.mvel2.optimizers.impl.refl.nodes.ArrayLength) StaticVarAccessor(org.mvel2.optimizers.impl.refl.nodes.StaticVarAccessor) Method(java.lang.reflect.Method) MapAccessorNest(org.mvel2.optimizers.impl.refl.nodes.MapAccessorNest) ArrayAccessor(org.mvel2.optimizers.impl.refl.nodes.ArrayAccessor) ClassUtils.convertToPrimitiveType(org.drools.core.util.ClassUtils.convertToPrimitiveType) Type(java.lang.reflect.Type) ParameterizedType(java.lang.reflect.ParameterizedType) ListAccessorNest(org.mvel2.optimizers.impl.refl.nodes.ListAccessorNest) ConstructorAccessor(org.mvel2.optimizers.impl.refl.nodes.ConstructorAccessor)

Example 5 with ArrayLength

use of org.mvel2.optimizers.impl.refl.nodes.ArrayLength in project mvel by mikebrock.

the class ReflectiveAccessorOptimizer method getMethod.

/**
 * Find an appropriate method, execute it, and return it's response.
 *
 * @param ctx  -
 * @param name -
 * @return -
 * @throws Exception -
 */
@SuppressWarnings({ "unchecked" })
private Object getMethod(Object ctx, String name) throws Exception {
    int st = cursor;
    String tk = cursor != end && expr[cursor] == '(' && ((cursor = balancedCapture(expr, cursor, '(')) - st) > 1 ? new String(expr, st + 1, cursor - st - 1) : "";
    cursor++;
    Object[] args;
    Class[] argTypes;
    ExecutableStatement[] es;
    if (tk.length() == 0) {
        args = ParseTools.EMPTY_OBJ_ARR;
        argTypes = ParseTools.EMPTY_CLS_ARR;
        es = null;
    } else {
        List<char[]> subtokens = parseParameterList(tk.toCharArray(), 0, -1);
        es = new ExecutableStatement[subtokens.size()];
        args = new Object[subtokens.size()];
        argTypes = new Class[subtokens.size()];
        for (int i = 0; i < subtokens.size(); i++) {
            try {
                args[i] = (es[i] = (ExecutableStatement) subCompileExpression(subtokens.get(i), pCtx)).getValue(this.thisRef, thisRef, variableFactory);
            } catch (CompileException e) {
                throw ErrorUtil.rewriteIfNeeded(e, this.expr, this.start);
            }
            if (es[i].isExplicitCast())
                argTypes[i] = es[i].getKnownEgressType();
        }
        if (pCtx.isStrictTypeEnforcement()) {
            for (int i = 0; i < args.length; i++) {
                argTypes[i] = es[i].getKnownEgressType();
            }
        } else {
            for (int i = 0; i < args.length; i++) {
                if (argTypes[i] != null)
                    continue;
                if (es[i].getKnownEgressType() == Object.class) {
                    argTypes[i] = args[i] == null ? null : args[i].getClass();
                } else {
                    argTypes[i] = es[i].getKnownEgressType();
                }
            }
        }
    }
    if (first && variableFactory != null && variableFactory.isResolveable(name)) {
        Object ptr = variableFactory.getVariableResolver(name).getValue();
        if (ptr instanceof Method) {
            ctx = ((Method) ptr).getDeclaringClass();
            name = ((Method) ptr).getName();
        } else if (ptr instanceof MethodStub) {
            ctx = ((MethodStub) ptr).getClassReference();
            name = ((MethodStub) ptr).getMethodName();
        } else if (ptr instanceof Function) {
            Function func = (Function) ptr;
            if (!name.equals(func.getName())) {
                getBeanProperty(ctx, name);
                addAccessorNode(new DynamicFunctionAccessor(es));
            } else {
                addAccessorNode(new FunctionAccessor((Function) ptr, es));
            }
            return ((Function) ptr).call(ctx, thisRef, variableFactory, args);
        } else {
            throw new OptimizationFailure("attempt to optimize a method call for a reference that does not point to a method: " + name + " (reference is type: " + (ctx != null ? ctx.getClass().getName() : null) + ")");
        }
        first = false;
    }
    if (ctx == null) {
        throw new PropertyAccessException("null pointer or function not found: " + name, this.expr, this.start);
    }
    boolean classTarget = false;
    Class<?> cls = currType != null ? currType : ((classTarget = ctx instanceof Class) ? (Class<?>) ctx : ctx.getClass());
    currType = null;
    Method m;
    Class[] parameterTypes = null;
    if ((m = getBestCandidate(argTypes, name, cls, cls.getMethods(), false, classTarget)) != null) {
        parameterTypes = m.getParameterTypes();
    }
    if (m == null && classTarget) {
        /**
         * If we didn't find anything, maybe we're looking for the actual java.lang.Class methods.
         */
        if ((m = getBestCandidate(argTypes, name, cls, Class.class.getMethods(), false)) != null) {
            parameterTypes = m.getParameterTypes();
        }
    }
    if (m == null) {
        StringAppender errorBuild = new StringAppender();
        if ("size".equals(name) && args.length == 0 && cls.isArray()) {
            addAccessorNode(new ArrayLength());
            return getLength(ctx);
        }
        for (int i = 0; i < args.length; i++) {
            errorBuild.append(args[i] != null ? args[i].getClass().getName() : null);
            if (i < args.length - 1)
                errorBuild.append(", ");
        }
        throw new PropertyAccessException("unable to resolve method: " + cls.getName() + "." + name + "(" + errorBuild.toString() + ") [arglength=" + args.length + "]", this.expr, this.st);
    } else {
        if (es != null) {
            ExecutableStatement cExpr;
            for (int i = 0; i < es.length; i++) {
                cExpr = (ExecutableStatement) es[i];
                if (cExpr.getKnownIngressType() == null) {
                    cExpr.setKnownIngressType(parameterTypes[i]);
                    cExpr.computeTypeConversionRule();
                }
                if (!cExpr.isConvertableIngressEgress()) {
                    args[i] = convert(args[i], parameterTypes[i]);
                }
            }
        } else {
            /**
             * Coerce any types if required.
             */
            for (int i = 0; i < args.length; i++) args[i] = convert(args[i], parameterTypes[i]);
        }
        Object o = getWidenedTarget(m).invoke(ctx, args);
        if (hasNullMethodHandler()) {
            addAccessorNode(new MethodAccessorNH(getWidenedTarget(m), (ExecutableStatement[]) es, getNullMethodHandler()));
            if (o == null)
                o = getNullMethodHandler().getProperty(m.getName(), ctx, variableFactory);
        } else {
            addAccessorNode(new MethodAccessor(getWidenedTarget(m), (ExecutableStatement[]) es));
        }
        /**
         * return the response.
         */
        return o;
    }
}
Also used : ExecutableStatement(org.mvel2.compiler.ExecutableStatement) Function(org.mvel2.ast.Function)

Aggregations

Method (java.lang.reflect.Method)6 ExecutableStatement (org.mvel2.compiler.ExecutableStatement)5 Field (java.lang.reflect.Field)4 ArrayLength (org.mvel2.optimizers.impl.refl.nodes.ArrayLength)4 MethodAccessor (org.mvel2.optimizers.impl.refl.nodes.MethodAccessor)4 Map (java.util.Map)3 CompileException (org.mvel2.CompileException)3 OptimizationFailure (org.mvel2.OptimizationFailure)3 PropertyAccessException (org.mvel2.PropertyAccessException)3 Label (org.mvel2.asm.Label)3 ExecutableAccessor (org.mvel2.compiler.ExecutableAccessor)3 ExecutableLiteral (org.mvel2.compiler.ExecutableLiteral)3 FieldAccessor (org.mvel2.optimizers.impl.refl.nodes.FieldAccessor)3 GetterAccessor (org.mvel2.optimizers.impl.refl.nodes.GetterAccessor)3 MapAccessor (org.mvel2.optimizers.impl.refl.nodes.MapAccessor)3 StaticVarAccessor (org.mvel2.optimizers.impl.refl.nodes.StaticVarAccessor)3 ThisValueAccessor (org.mvel2.optimizers.impl.refl.nodes.ThisValueAccessor)3 IOException (java.io.IOException)2 Constructor (java.lang.reflect.Constructor)2 Member (java.lang.reflect.Member)2