0001: /**
0002: * MVEL (The MVFLEX Expression Language)
0003: *
0004: * Copyright (C) 2007 Christopher Brock, MVFLEX/Valhalla Project and the Codehaus
0005: *
0006: * Licensed under the Apache License, Version 2.0 (the "License");
0007: * you may not use this file except in compliance with the License.
0008: * You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing, software
0013: * distributed under the License is distributed on an "AS IS" BASIS,
0014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0015: * See the License for the specific language governing permissions and
0016: * limitations under the License.
0017: *
0018: */package org.mvel.optimizers.impl.asm;
0019:
0020: import org.mvel.*;
0021: import static org.mvel.DataConversion.canConvert;
0022: import static org.mvel.DataConversion.convert;
0023: import static org.mvel.MVEL.isAdvancedDebugging;
0024: import org.mvel.asm.ClassWriter;
0025: import org.mvel.asm.Label;
0026: import org.mvel.asm.MethodVisitor;
0027: import org.mvel.asm.Opcodes;
0028: import static org.mvel.asm.Opcodes.*;
0029: import static org.mvel.asm.Type.*;
0030: import org.mvel.ast.Function;
0031: import org.mvel.compiler.Accessor;
0032: import org.mvel.compiler.ExecutableLiteral;
0033: import org.mvel.compiler.ExecutableStatement;
0034: import org.mvel.integration.VariableResolverFactory;
0035: import org.mvel.optimizers.AbstractOptimizer;
0036: import org.mvel.optimizers.AccessorOptimizer;
0037: import org.mvel.optimizers.OptimizationNotSupported;
0038: import org.mvel.optimizers.impl.refl.Union;
0039: import static org.mvel.util.ArrayTools.findFirst;
0040: import org.mvel.util.*;
0041: import static org.mvel.util.ParseTools.*;
0042:
0043: import java.io.FileWriter;
0044: import java.io.IOException;
0045: import static java.lang.System.getProperty;
0046: import static java.lang.reflect.Array.getLength;
0047: import java.lang.reflect.*;
0048: import java.util.ArrayList;
0049: import java.util.Arrays;
0050: import java.util.List;
0051: import java.util.Map;
0052:
0053: /**
0054: * Implementation of the MVEL Just-in-Time (JIT) compiler for Property Accessors using the ASM bytecode
0055: * engineering library.
0056: * <p/>
0057: * TODO: This class needs serious re-factoring.
0058: */
0059: @SuppressWarnings({"TypeParameterExplicitlyExtendsObject","unchecked","UnusedDeclaration"})
0060: public class ASMAccessorOptimizer extends AbstractOptimizer implements
0061: AccessorOptimizer {
0062: private static final String MAP_IMPL = "java/util/HashMap";
0063: private static final String LIST_IMPL = "org/mvel/util/FastList";
0064:
0065: private static final int OPCODES_VERSION;
0066:
0067: static {
0068: final String javaVersion = getProperty("java.version");
0069: if (javaVersion.startsWith("1.4"))
0070: OPCODES_VERSION = Opcodes.V1_4;
0071: else if (javaVersion.startsWith("1.5"))
0072: OPCODES_VERSION = Opcodes.V1_5;
0073: else if (javaVersion.startsWith("1.6")
0074: || javaVersion.startsWith("1.7"))
0075: OPCODES_VERSION = Opcodes.V1_6;
0076: else
0077: OPCODES_VERSION = Opcodes.V1_2;
0078: }
0079:
0080: private Object ctx;
0081: private Object this Ref;
0082:
0083: private VariableResolverFactory variableFactory;
0084:
0085: private static final Object[] EMPTYARG = new Object[0];
0086: private static final Class[] EMPTYCLS = new Class[0];
0087:
0088: private boolean first = true;
0089: private boolean deferFinish = false;
0090: private boolean literal = false;
0091:
0092: private String className;
0093: private ClassWriter cw;
0094: private MethodVisitor mv;
0095:
0096: private Object val;
0097: private int stacksize = 1;
0098: private int maxlocals = 1;
0099: private long time;
0100:
0101: private ArrayList<ExecutableStatement> compiledInputs;
0102:
0103: private Class returnType;
0104:
0105: @SuppressWarnings({"StringBufferField"})
0106: private StringAppender buildLog;
0107:
0108: public ASMAccessorOptimizer() {
0109: //do this to confirm we're running the correct version
0110: //otherwise should create a verification error in VM
0111: new ClassWriter(ClassWriter.COMPUTE_MAXS);
0112: }
0113:
0114: /**
0115: * Does all the boilerplate for initiating the JIT.
0116: */
0117: private void _initJIT() {
0118: if (isAdvancedDebugging()) {
0119: buildLog = new StringAppender();
0120: }
0121:
0122: cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
0123: + ClassWriter.COMPUTE_FRAMES);
0124:
0125: synchronized (Runtime.getRuntime()) {
0126: int r = (int) Math.random() * 100;
0127: cw.visit(OPCODES_VERSION, Opcodes.ACC_PUBLIC
0128: + Opcodes.ACC_SUPER, className = "ASMAccessorImpl_"
0129: + String.valueOf(cw.hashCode()).replaceAll("\\-",
0130: "_") + (System.currentTimeMillis() / 10)
0131: + r, null, "java/lang/Object",
0132: new String[] { "org/mvel/compiler/Accessor" });
0133: }
0134:
0135: MethodVisitor m = cw.visitMethod(ACC_PUBLIC, "<init>", "()V",
0136: null, null);
0137: m.visitCode();
0138: m.visitVarInsn(Opcodes.ALOAD, 0);
0139: m.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>",
0140: "()V");
0141: m.visitInsn(RETURN);
0142:
0143: m.visitMaxs(1, 1);
0144: m.visitEnd();
0145:
0146: mv = cw
0147: .visitMethod(
0148: ACC_PUBLIC,
0149: "getValue",
0150: "(Ljava/lang/Object;Ljava/lang/Object;Lorg/mvel/integration/VariableResolverFactory;)Ljava/lang/Object;",
0151: null, null);
0152: mv.visitCode();
0153: }
0154:
0155: public Accessor optimizeAccessor(char[] property,
0156: Object staticContext, Object this Ref,
0157: VariableResolverFactory factory, boolean root) {
0158: time = System.currentTimeMillis();
0159:
0160: //inputs = 0;
0161: compiledInputs = new ArrayList<ExecutableStatement>();
0162:
0163: start = cursor = 0;
0164:
0165: this .first = true;
0166: this .val = null;
0167:
0168: this .length = property.length;
0169: this .expr = property;
0170: this .ctx = staticContext;
0171: this .this Ref = this Ref;
0172: this .variableFactory = factory;
0173:
0174: _initJIT();
0175:
0176: return compileAccessor();
0177: }
0178:
0179: public SetAccessor optimizeSetAccessor(char[] property, Object ctx,
0180: Object this Ref, VariableResolverFactory factory,
0181: boolean rootThisRef, Object value) {
0182: throw new RuntimeException("not implemented");
0183: }
0184:
0185: private void _finishJIT() {
0186: if (!deferFinish) {
0187:
0188: if (returnType != null && returnType.isPrimitive()) {
0189: //noinspection unchecked
0190: wrapPrimitive(returnType);
0191: }
0192:
0193: if (returnType == void.class) {
0194: assert debug("ACONST_NULL");
0195: mv.visitInsn(ACONST_NULL);
0196: }
0197:
0198: assert debug("ARETURN");
0199:
0200: mv.visitInsn(ARETURN);
0201: }
0202:
0203: assert debug("\n{METHOD STATS (maxstack=" + stacksize + ")}\n");
0204: mv.visitMaxs(stacksize, maxlocals);
0205:
0206: mv.visitEnd();
0207:
0208: buildInputs();
0209:
0210: cw.visitEnd();
0211:
0212: dumpAdvancedDebugging(); // dump advanced debugging if necessary
0213: }
0214:
0215: private Accessor _initializeAccessor() throws Exception {
0216:
0217: /**
0218: * Hot load the class we just generated.
0219: */
0220: Class cls = loadClass(className, cw.toByteArray());
0221:
0222: assert debug("[MVEL JIT Completed Optimization <<"
0223: + new String(expr) + ">>]::" + cls + " (time: "
0224: + (System.currentTimeMillis() - time) + "ms)");
0225:
0226: Object o;
0227:
0228: try {
0229: if (compiledInputs.size() == 0) {
0230: o = cls.newInstance();
0231: } else {
0232: Class[] parms = new Class[compiledInputs.size()];
0233: for (int i = 0; i < compiledInputs.size(); i++) {
0234: parms[i] = ExecutableStatement.class;
0235: }
0236: o = cls
0237: .getConstructor(parms)
0238: .newInstance(
0239: compiledInputs
0240: .toArray(new ExecutableStatement[compiledInputs
0241: .size()]));
0242: }
0243: } catch (VerifyError e) {
0244: System.out
0245: .println("**** COMPILER BUG! REPORT THIS IMMEDIATELY AT http://jira.codehaus.org/browse/mvel");
0246: System.out.println("Expression: " + new String(expr));
0247: throw e;
0248: }
0249:
0250: if (!(o instanceof Accessor)) {
0251: dumpAdvancedDebugging();
0252: throw new RuntimeException(
0253: "Classloader problem detected. JIT Class is not subclass of org.mvel.compiler.Accessor.");
0254: }
0255:
0256: return (Accessor) o;
0257: }
0258:
0259: private Accessor compileAccessor() {
0260: assert debug("<<INITIATE COMPILE>>");
0261:
0262: Object curr = ctx;
0263:
0264: try {
0265: while (cursor < length) {
0266: switch (nextSubToken()) {
0267: case BEAN:
0268: curr = getBeanProperty(curr, capture());
0269: break;
0270: case METH:
0271: curr = getMethod(curr, capture());
0272: break;
0273: case COL:
0274: curr = getCollectionProperty(curr, capture());
0275: break;
0276: }
0277:
0278: // check to see if a null safety is enabled on this property.
0279: if (fields == -1) {
0280: if (curr == null) {
0281: break;
0282: } else {
0283: fields = 0;
0284: }
0285: }
0286:
0287: first = false;
0288: }
0289:
0290: val = curr;
0291:
0292: _finishJIT();
0293:
0294: return _initializeAccessor();
0295: } catch (InvocationTargetException e) {
0296: throw new PropertyAccessException(new String(expr), e);
0297: } catch (IllegalAccessException e) {
0298: throw new PropertyAccessException(new String(expr), e);
0299: } catch (IndexOutOfBoundsException e) {
0300: throw new PropertyAccessException(new String(expr), e);
0301: } catch (PropertyAccessException e) {
0302: // throw new PropertyAccessException(e.getMessage(), e);
0303: throw new CompileException(e.getMessage(), e);
0304: } catch (CompileException e) {
0305: throw e;
0306: } catch (NullPointerException e) {
0307: throw new PropertyAccessException(new String(expr), e);
0308: } catch (OptimizationNotSupported e) {
0309: throw e;
0310: } catch (Exception e) {
0311: // throw new PropertyAccessException(new String(expr), e);
0312: throw new CompileException(e.getMessage(), e);
0313: }
0314: }
0315:
0316: private Object getBeanProperty(Object ctx, String property)
0317: throws IllegalAccessException, InvocationTargetException {
0318:
0319: assert debug("\n ** ENTER -> {bean: " + property + "; ctx="
0320: + ctx + "}");
0321:
0322: if (returnType != null && returnType.isPrimitive()) {
0323: //noinspection unchecked
0324: wrapPrimitive(returnType);
0325: }
0326:
0327: Class cls = (ctx instanceof Class ? ((Class) ctx)
0328: : ctx != null ? ctx.getClass() : null);
0329: Member member = cls != null ? PropertyTools.getFieldOrAccessor(
0330: cls, property) : null;
0331:
0332: if (first) {
0333: if ("this".equals(property)) {
0334: assert debug("ALOAD 2");
0335: mv.visitVarInsn(ALOAD, 2);
0336: return this Ref;
0337: } else if (variableFactory != null
0338: && variableFactory.isResolveable(property)) {
0339: if (variableFactory.isIndexedFactory()
0340: && variableFactory.isTarget(property)) {
0341: int idx;
0342: try {
0343: loadVariableByIndex(idx = variableFactory
0344: .variableIndexOf(property));
0345: } catch (Exception e) {
0346: throw new OptimizationFailure(property);
0347: }
0348:
0349: return variableFactory.getIndexedVariableResolver(
0350: idx).getValue();
0351: } else {
0352: try {
0353: loadVariableByName(property);
0354: } catch (Exception e) {
0355: throw new OptimizationFailure(
0356: "critical error in JIT", e);
0357: }
0358:
0359: return variableFactory
0360: .getVariableResolver(property).getValue();
0361: }
0362: } else {
0363: assert debug("ALOAD 1");
0364: mv.visitVarInsn(ALOAD, 1);
0365: }
0366: }
0367:
0368: if (member instanceof Field) {
0369: Object o = ((Field) member).get(ctx);
0370:
0371: if (first) {
0372: assert debug("ALOAD 1 (A)");
0373: mv.visitVarInsn(ALOAD, 1);
0374: }
0375:
0376: if (((member.getModifiers() & Modifier.STATIC) != 0)) {
0377: assert debug("GETSTATIC "
0378: + getDescriptor(member.getDeclaringClass())
0379: + "." + member.getName() + "::"
0380: + getDescriptor(((Field) member).getType()));
0381:
0382: mv.visitFieldInsn(GETSTATIC, getInternalName(member
0383: .getDeclaringClass()), member.getName(),
0384: getDescriptor(returnType = ((Field) member)
0385: .getType()));
0386: } else {
0387: assert debug("CHECKCAST " + getInternalName(cls));
0388: mv.visitTypeInsn(CHECKCAST, getInternalName(cls));
0389:
0390: assert debug("GETFIELD " + property + ":"
0391: + getDescriptor(((Field) member).getType()));
0392: mv.visitFieldInsn(GETFIELD, getInternalName(cls),
0393: property,
0394: getDescriptor(returnType = ((Field) member)
0395: .getType()));
0396: }
0397:
0398: returnType = ((Field) member).getType();
0399:
0400: return o;
0401: } else if (member != null) {
0402: Object o;
0403:
0404: if (first) {
0405: assert debug("ALOAD 1 (B)");
0406: mv.visitVarInsn(ALOAD, 1);
0407: }
0408:
0409: try {
0410: o = ((Method) member).invoke(ctx, EMPTYARG);
0411:
0412: if (returnType != member.getDeclaringClass()) {
0413: assert debug("CHECKCAST "
0414: + getInternalName(member
0415: .getDeclaringClass()));
0416: mv.visitTypeInsn(CHECKCAST, getInternalName(member
0417: .getDeclaringClass()));
0418: }
0419:
0420: returnType = ((Method) member).getReturnType();
0421:
0422: assert debug("INVOKEVIRTUAL " + member.getName() + ":"
0423: + returnType);
0424: mv.visitMethodInsn(INVOKEVIRTUAL,
0425: getInternalName(member.getDeclaringClass()),
0426: member.getName(),
0427: getMethodDescriptor((Method) member));
0428: } catch (IllegalAccessException e) {
0429: Method iFaceMeth = determineActualTargetMethod((Method) member);
0430:
0431: assert debug("CHECKCAST "
0432: + getInternalName(iFaceMeth.getDeclaringClass()));
0433: mv.visitTypeInsn(CHECKCAST, getInternalName(iFaceMeth
0434: .getDeclaringClass()));
0435:
0436: returnType = iFaceMeth.getReturnType();
0437:
0438: assert debug("INVOKEINTERFACE " + member.getName()
0439: + ":" + returnType);
0440: mv.visitMethodInsn(INVOKEINTERFACE,
0441: getInternalName(iFaceMeth.getDeclaringClass()),
0442: member.getName(),
0443: getMethodDescriptor((Method) member));
0444:
0445: o = iFaceMeth.invoke(ctx, EMPTYARG);
0446: }
0447: return o;
0448:
0449: } else if (ctx instanceof Map
0450: && ((Map) ctx).containsKey(property)) {
0451: assert debug("CHECKCAST java/util/Map");
0452: mv.visitTypeInsn(CHECKCAST, "java/util/Map");
0453:
0454: assert debug("LDC: \"" + property + "\"");
0455: mv.visitLdcInsn(property);
0456:
0457: assert debug("INVOKEINTERFACE: get");
0458: mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get",
0459: "(Ljava/lang/Object;)Ljava/lang/Object;");
0460: return ((Map) ctx).get(property);
0461: } else if (first && "this".equals(property)) {
0462: assert debug("ALOAD 2");
0463: mv.visitVarInsn(ALOAD, 2); // load the thisRef value.
0464:
0465: return this .this Ref;
0466: } else if ("length".equals(property)
0467: && ctx.getClass().isArray()) {
0468: anyArrayCheck(ctx.getClass());
0469:
0470: assert debug("ARRAYLENGTH");
0471: mv.visitInsn(ARRAYLENGTH);
0472:
0473: wrapPrimitive(int.class);
0474: return getLength(ctx);
0475: } else if (LITERALS.containsKey(property)) {
0476: Object lit = LITERALS.get(property);
0477:
0478: if (lit instanceof Class) {
0479: ldcClassConstant((Class) lit);
0480: }
0481:
0482: return LITERALS.get(property);
0483: } else if (ctx == null) {
0484: throw new NullPointerException("parent field of '"
0485: + property + "' is null in: " + new String(expr));
0486: } else {
0487: Object ts = tryStaticAccess();
0488:
0489: if (ts != null) {
0490: if (ts instanceof Class) {
0491: ldcClassConstant((Class) ts);
0492: return ts;
0493: } else if (ts instanceof Method) {
0494: writeFunctionPointerStub(((Method) ts)
0495: .getDeclaringClass(), (Method) ts);
0496: return ts;
0497: } else {
0498: assert debug("GETSTATIC "
0499: + getDescriptor(((Field) ts)
0500: .getDeclaringClass()) + "."
0501: + ((Field) ts).getName() + "::"
0502: + getDescriptor(((Field) ts).getType()));
0503:
0504: mv.visitFieldInsn(GETSTATIC,
0505: getDescriptor(((Field) ts)
0506: .getDeclaringClass()), ((Field) ts)
0507: .getName(),
0508: getDescriptor(returnType = ((Field) ts)
0509: .getType()));
0510:
0511: return ((Field) ts).get(null);
0512: }
0513: } else if (ctx instanceof Class) {
0514: /**
0515: * This is our ugly support for function pointers. This works but needs to be re-thought out at some
0516: * point.
0517: */
0518: Class c = (Class) ctx;
0519: for (Method m : c.getMethods()) {
0520: if (property.equals(m.getName())) {
0521: writeFunctionPointerStub(c, m);
0522: return m;
0523: }
0524: }
0525: }
0526:
0527: throw new PropertyAccessException(property);
0528: }
0529: }
0530:
0531: private void writeFunctionPointerStub(Class c, Method m) {
0532: ldcClassConstant(c);
0533:
0534: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class",
0535: "getMethods", "()[Ljava/lang/reflect/Method;");
0536: mv.visitVarInsn(ASTORE, 7);
0537: mv.visitInsn(ICONST_0);
0538: mv.visitVarInsn(ISTORE, 5);
0539: mv.visitVarInsn(ALOAD, 7);
0540: mv.visitInsn(ARRAYLENGTH);
0541: mv.visitVarInsn(ISTORE, 6);
0542: Label l1 = new Label();
0543: mv.visitJumpInsn(GOTO, l1);
0544: Label l2 = new Label();
0545: mv.visitLabel(l2);
0546: mv.visitVarInsn(ALOAD, 7);
0547: mv.visitVarInsn(ILOAD, 5);
0548: mv.visitInsn(AALOAD);
0549: mv.visitVarInsn(ASTORE, 4);
0550: Label l3 = new Label();
0551: mv.visitLabel(l3);
0552: mv.visitLdcInsn(m.getName());
0553: mv.visitVarInsn(ALOAD, 4);
0554: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method",
0555: "getName", "()Ljava/lang/String;");
0556: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals",
0557: "(Ljava/lang/Object;)Z");
0558: Label l4 = new Label();
0559: mv.visitJumpInsn(IFEQ, l4);
0560: Label l5 = new Label();
0561: mv.visitLabel(l5);
0562: mv.visitVarInsn(ALOAD, 4);
0563: mv.visitInsn(ARETURN);
0564: mv.visitLabel(l4);
0565: mv.visitIincInsn(5, 1);
0566: mv.visitLabel(l1);
0567: mv.visitVarInsn(ILOAD, 5);
0568: mv.visitVarInsn(ILOAD, 6);
0569: mv.visitJumpInsn(IF_ICMPLT, l2);
0570: Label l6 = new Label();
0571: mv.visitLabel(l6);
0572: mv.visitInsn(ACONST_NULL);
0573: mv.visitInsn(ARETURN);
0574:
0575: deferFinish = true;
0576: }
0577:
0578: private Object getCollectionProperty(Object ctx, String prop)
0579: throws IllegalAccessException, InvocationTargetException {
0580: if (prop.length() > 0)
0581: ctx = getBeanProperty(ctx, prop);
0582:
0583: assert debug("\n ** ENTER -> {collections: " + prop
0584: + "; ctx=" + ctx + "}");
0585:
0586: int start = ++cursor;
0587:
0588: whiteSpaceSkip();
0589:
0590: if (cursor == length)
0591: throw new CompileException("unterminated '['");
0592:
0593: if (!scanTo(']'))
0594: throw new CompileException("unterminated '['");
0595:
0596: String tk = new String(expr, start, cursor - start);
0597:
0598: assert debug("{collection token:<<" + tk + ">>}");
0599:
0600: ExecutableStatement compiled = (ExecutableStatement) subCompileExpression(tk);
0601: Object item = compiled.getValue(ctx, variableFactory);
0602:
0603: ++cursor;
0604:
0605: if (ctx instanceof Map) {
0606: assert debug("CHECKCAST java/util/Map");
0607: mv.visitTypeInsn(CHECKCAST, "java/util/Map");
0608:
0609: Class c = writeLiteralOrSubexpression(compiled);
0610: if (c != null && c.isPrimitive()) {
0611: wrapPrimitive(c);
0612: }
0613:
0614: assert debug("INVOKEINTERFACE: get");
0615: mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get",
0616: "(Ljava/lang/Object;)Ljava/lang/Object;");
0617:
0618: return ((Map) ctx).get(item);
0619: } else if (ctx instanceof List) {
0620: assert debug("CHECKCAST java/util/List");
0621: mv.visitTypeInsn(CHECKCAST, "java/util/List");
0622:
0623: writeLiteralOrSubexpression(compiled, int.class);
0624:
0625: assert debug("INVOKEINTERFACE: java/util/List.get");
0626: mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List",
0627: "get", "(I)Ljava/lang/Object;");
0628:
0629: return ((List) ctx).get(convert(item, Integer.class));
0630:
0631: } else if (ctx instanceof Object[]) {
0632: assert debug("CHECKCAST [Ljava/lang/Object;");
0633: mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
0634:
0635: writeLiteralOrSubexpression(compiled, int.class, item
0636: .getClass());
0637:
0638: assert debug("AALOAD");
0639: mv.visitInsn(AALOAD);
0640:
0641: return ((Object[]) ctx)[convert(item, Integer.class)];
0642: } else if (ctx instanceof CharSequence) {
0643:
0644: assert debug("CHECKCAST java/lang/CharSequence");
0645: mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence");
0646:
0647: if (item instanceof Integer) {
0648: intPush((Integer) item);
0649:
0650: assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
0651: mv.visitMethodInsn(INVOKEINTERFACE,
0652: "java/lang/CharSequence", "charAt", "(I)C");
0653:
0654: wrapPrimitive(char.class);
0655:
0656: return ((CharSequence) ctx).charAt((Integer) item);
0657: } else {
0658: writeLiteralOrSubexpression(compiled, Integer.class);
0659: unwrapPrimitive(int.class);
0660:
0661: assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
0662: mv.visitMethodInsn(INVOKEINTERFACE,
0663: "java/lang/CharSequence", "charAt", "(I)C");
0664:
0665: wrapPrimitive(char.class);
0666:
0667: return ((CharSequence) ctx).charAt(convert(item,
0668: Integer.class));
0669:
0670: }
0671: } else {
0672: throw new CompileException(
0673: "illegal use of []: unknown type: "
0674: + (ctx == null ? null : ctx.getClass()
0675: .getName()));
0676: }
0677: }
0678:
0679: @SuppressWarnings({"unchecked"})
0680: private Object getMethod(Object ctx, String name)
0681: throws IllegalAccessException, InvocationTargetException {
0682: assert debug("\n ** {method: " + name + "}");
0683:
0684: int st = cursor;
0685: String tk = ((cursor = ParseTools.balancedCapture(expr, cursor,
0686: '(')) - st) > 1 ? new String(expr, st + 1, cursor - st
0687: - 1) : "";
0688: cursor++;
0689:
0690: Object[] preConvArgs;
0691: Object[] args;
0692: ExecutableStatement[] es;
0693:
0694: if (tk.length() == 0) {
0695: //noinspection ZeroLengthArrayAllocation
0696: args = new Object[0];
0697:
0698: //noinspection ZeroLengthArrayAllocation
0699: preConvArgs = new Object[0];
0700: es = null;
0701: } else {
0702: String[] subtokens = parseParameterList(tk.toCharArray(),
0703: 0, -1);
0704:
0705: es = new ExecutableStatement[subtokens.length];
0706: args = new Object[subtokens.length];
0707: preConvArgs = new Object[es.length];
0708:
0709: for (int i = 0; i < subtokens.length; i++) {
0710: preConvArgs[i] = args[i] = (es[i] = (ExecutableStatement) subCompileExpression(subtokens[i]))
0711: .getValue(this .ctx, this .this Ref,
0712: variableFactory);
0713: }
0714: }
0715:
0716: if (first && variableFactory != null
0717: && variableFactory.isResolveable(name)) {
0718: Object ptr = variableFactory.getVariableResolver(name)
0719: .getValue();
0720:
0721: if (ptr instanceof Method) {
0722: ctx = ((Method) ptr).getDeclaringClass();
0723: name = ((Method) ptr).getName();
0724: } else if (ptr instanceof MethodStub) {
0725: ctx = ((MethodStub) ptr).getClassReference();
0726: name = ((MethodStub) ptr).getMethodName();
0727: } else if (ptr instanceof Function) {
0728:
0729: if (es != null && es.length != 0) {
0730: compiledInputs.addAll(Arrays.asList(es));
0731:
0732: intPush(es.length);
0733:
0734: assert debug("ANEWARRAY [" + es.length + "]");
0735: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
0736:
0737: assert debug("ASTORE 4");
0738: mv.visitVarInsn(ASTORE, 4);
0739:
0740: for (int i = 0; i < es.length; i++) {
0741: assert debug("ALOAD 4");
0742: mv.visitVarInsn(ALOAD, 4);
0743: intPush(i);
0744: loadField(i);
0745:
0746: assert debug("ALOAD 1");
0747: mv.visitVarInsn(ALOAD, 1);
0748:
0749: assert debug("ALOAD 3");
0750: mv.visitIntInsn(ALOAD, 3);
0751:
0752: assert debug("INVOKEINTERFACE ExecutableStatement.getValue");
0753: mv
0754: .visitMethodInsn(
0755: INVOKEINTERFACE,
0756: "org/mvel/compiler/ExecutableStatement",
0757: "getValue",
0758: "(Ljava/lang/Object;Lorg/mvel/integration/VariableResolverFactory;)Ljava/lang/Object;");
0759:
0760: assert debug("AASTORE");
0761: mv.visitInsn(AASTORE);
0762: }
0763:
0764: } else {
0765: assert debug("ACONST_NULL");
0766: mv.visitInsn(ACONST_NULL);
0767:
0768: assert debug("CHECKCAST java/lang/Object");
0769: mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
0770:
0771: assert debug("ASTORE 4");
0772: mv.visitVarInsn(ASTORE, 4);
0773: }
0774:
0775: if (variableFactory.isIndexedFactory()
0776: && variableFactory.isTarget(name)) {
0777: loadVariableByIndex(variableFactory
0778: .variableIndexOf(name));
0779: } else {
0780: loadVariableByName(name);
0781: }
0782:
0783: checkcast(Function.class);
0784:
0785: assert debug("ALOAD 1");
0786: mv.visitVarInsn(ALOAD, 1);
0787:
0788: assert debug("ALOAD 2");
0789: mv.visitVarInsn(ALOAD, 2);
0790:
0791: assert debug("ALOAD 3");
0792: mv.visitVarInsn(ALOAD, 3);
0793:
0794: assert debug("ALOAD 4");
0795: mv.visitVarInsn(ALOAD, 4);
0796:
0797: assert debug("INVOKEVIRTUAL Function.call");
0798: mv
0799: .visitMethodInsn(
0800: INVOKEVIRTUAL,
0801: getInternalName(Function.class),
0802: "call",
0803: "(Ljava/lang/Object;Ljava/lang/Object;Lorg/mvel/integration/VariableResolverFactory;[Ljava/lang/Object;)Ljava/lang/Object;");
0804:
0805: Object[] parm = null;
0806:
0807: if (es != null) {
0808: parm = new Object[es.length];
0809: for (int i = 0; i < es.length; i++) {
0810: parm[i] = es[i].getValue(ctx, this Ref,
0811: variableFactory);
0812: }
0813: }
0814:
0815: return ((Function) ptr).call(ctx, this Ref,
0816: variableFactory, parm);
0817: } else {
0818: throw new OptimizationFailure(
0819: "attempt to optimize a method call for a reference that does not point to a method: "
0820: + name
0821: + " (reference is type: "
0822: + (ctx != null ? ctx.getClass()
0823: .getName() : null) + ")");
0824: }
0825:
0826: first = false;
0827: } else if (returnType != null && returnType.isPrimitive()) {
0828: //noinspection unchecked
0829: wrapPrimitive(returnType);
0830: }
0831:
0832: int inputsOffset = compiledInputs.size();
0833:
0834: if (es != null) {
0835: for (ExecutableStatement e : es) {
0836: if (e instanceof ExecutableLiteral) {
0837: continue;
0838: }
0839:
0840: compiledInputs.add(e);
0841: }
0842: }
0843:
0844: if (first) {
0845: assert debug("ALOAD 1 (D) ");
0846: mv.visitVarInsn(ALOAD, 1);
0847: }
0848:
0849: /**
0850: * If the target object is an instance of java.lang.Class itself then do not
0851: * adjust the Class scope target.
0852: */
0853: Class cls = ctx instanceof Class ? (Class) ctx : ctx.getClass();
0854:
0855: Method m;
0856: Class[] parameterTypes = null;
0857:
0858: /**
0859: * Try to find an instance method from the class target.
0860: */
0861: if ((m = getBestCandidate(args, name, cls, cls.getMethods())) != null) {
0862: parameterTypes = m.getParameterTypes();
0863: }
0864:
0865: if (m == null) {
0866: /**
0867: * If we didn't find anything, maybe we're looking for the actual java.lang.Class methods.
0868: */
0869: if ((m = getBestCandidate(args, name, cls, cls.getClass()
0870: .getDeclaredMethods())) != null) {
0871: parameterTypes = m.getParameterTypes();
0872: }
0873: }
0874:
0875: if (m == null) {
0876: StringAppender errorBuild = new StringAppender();
0877:
0878: if (parameterTypes != null) {
0879: for (int i = 0; i < args.length; i++) {
0880: errorBuild
0881: .append(parameterTypes[i] != null ? parameterTypes[i]
0882: .getClass().getName()
0883: : null);
0884: if (i < args.length - 1)
0885: errorBuild.append(", ");
0886: }
0887: }
0888:
0889: if ("size".equals(name) && args.length == 0
0890: && cls.isArray()) {
0891: anyArrayCheck(cls);
0892:
0893: assert debug("ARRAYLENGTH");
0894: mv.visitInsn(ARRAYLENGTH);
0895:
0896: wrapPrimitive(int.class);
0897: return getLength(ctx);
0898: }
0899:
0900: throw new CompileException("unable to resolve method: "
0901: + cls.getName() + "." + name + "("
0902: + errorBuild.toString() + ") [arglength="
0903: + args.length + "]");
0904: } else {
0905: m = getWidenedTarget(m);
0906:
0907: if (es != null) {
0908: ExecutableStatement cExpr;
0909: for (int i = 0; i < es.length; i++) {
0910: if ((cExpr = es[i]).getKnownIngressType() == null) {
0911: cExpr.setKnownIngressType(parameterTypes[i]);
0912: cExpr.computeTypeConversionRule();
0913: }
0914: if (!cExpr.isConvertableIngressEgress()) {
0915: args[i] = convert(args[i], parameterTypes[i]);
0916: }
0917: }
0918: } else {
0919: /**
0920: * Coerce any types if required.
0921: */
0922: for (int i = 0; i < args.length; i++) {
0923: args[i] = convert(args[i], parameterTypes[i]);
0924: }
0925: }
0926:
0927: if (m.getParameterTypes().length == 0) {
0928: if ((m.getModifiers() & Modifier.STATIC) != 0) {
0929: assert debug("INVOKESTATIC " + m.getName());
0930: mv.visitMethodInsn(INVOKESTATIC, getInternalName(m
0931: .getDeclaringClass()), m.getName(),
0932: getMethodDescriptor(m));
0933: } else {
0934: assert debug("CHECKCAST "
0935: + getInternalName(m.getDeclaringClass()));
0936: mv.visitTypeInsn(CHECKCAST, getInternalName(m
0937: .getDeclaringClass()));
0938:
0939: if (m.getDeclaringClass().isInterface()) {
0940: assert debug("INVOKEINTERFACE " + m.getName());
0941: mv.visitMethodInsn(INVOKEINTERFACE,
0942: getInternalName(m.getDeclaringClass()),
0943: m.getName(), getMethodDescriptor(m));
0944:
0945: } else {
0946: assert debug("INVOKEVIRTUAL " + m.getName());
0947: mv.visitMethodInsn(INVOKEVIRTUAL,
0948: getInternalName(m.getDeclaringClass()),
0949: m.getName(), getMethodDescriptor(m));
0950: }
0951: }
0952:
0953: returnType = m.getReturnType();
0954:
0955: stacksize++;
0956: } else {
0957: if ((m.getModifiers() & Modifier.STATIC) == 0) {
0958: assert debug("CHECKCAST " + getInternalName(cls));
0959: mv.visitTypeInsn(CHECKCAST, getInternalName(cls));
0960: }
0961:
0962: for (int i = 0; i < es.length; i++) {
0963: if (es[i] instanceof ExecutableLiteral) {
0964: ExecutableLiteral literal = (ExecutableLiteral) es[i];
0965:
0966: if (literal.getLiteral() == null) {
0967: assert debug("ICONST_NULL");
0968: mv.visitInsn(ACONST_NULL);
0969: continue;
0970: } else if (parameterTypes[i] == int.class
0971: && literal.intOptimized()) {
0972: intPush(literal.getInteger32());
0973: continue;
0974: } else if (parameterTypes[i] == int.class
0975: && preConvArgs[i] instanceof Integer) {
0976: intPush((Integer) preConvArgs[i]);
0977: continue;
0978: } else if (parameterTypes[i] == boolean.class) {
0979: boolean bool = DataConversion
0980: .convert(literal.getLiteral(),
0981: Boolean.class);
0982: assert debug(bool ? "ICONST_1" : "ICONST_0");
0983: mv.visitInsn(bool ? ICONST_1 : ICONST_0);
0984: continue;
0985: } else {
0986: Object lit = literal.getLiteral();
0987:
0988: if (parameterTypes[i] == Object.class) {
0989: if (isPrimitiveWrapper(lit.getClass())) {
0990: if (lit.getClass() == Integer.class) {
0991: intPush((Integer) lit);
0992: } else {
0993: assert debug("LDC " + lit);
0994: mv.visitLdcInsn(lit);
0995: }
0996:
0997: wrapPrimitive(lit.getClass());
0998: } else if (lit instanceof String) {
0999: mv.visitLdcInsn(lit);
1000: checkcast(Object.class);
1001: }
1002: continue;
1003: } else if (canConvert(parameterTypes[i],
1004: lit.getClass())) {
1005: assert debug("LDC " + lit + " ("
1006: + lit.getClass().getName()
1007: + ")");
1008: mv.visitLdcInsn(convert(lit,
1009: parameterTypes[i]));
1010: continue;
1011: }
1012: }
1013: }
1014:
1015: assert debug("ALOAD 0");
1016: mv.visitVarInsn(ALOAD, 0);
1017:
1018: assert debug("GETFIELD p" + inputsOffset);
1019: mv.visitFieldInsn(GETFIELD, className, "p"
1020: + inputsOffset,
1021: "Lorg/mvel/compiler/ExecutableStatement;");
1022:
1023: inputsOffset++;
1024:
1025: assert debug("ALOAD 2");
1026: mv.visitVarInsn(ALOAD, 2);
1027:
1028: assert debug("ALOAD 3");
1029: mv.visitVarInsn(ALOAD, 3);
1030:
1031: assert debug("INVOKEINTERFACE ExecutableStatement.getValue");
1032: mv
1033: .visitMethodInsn(
1034: INVOKEINTERFACE,
1035: getInternalName(ExecutableStatement.class),
1036: "getValue",
1037: "(Ljava/lang/Object;Lorg/mvel/integration/VariableResolverFactory;)Ljava/lang/Object;");
1038:
1039: if (parameterTypes[i].isPrimitive()) {
1040: if (preConvArgs[i] == null
1041: || (parameterTypes[i] != String.class && !parameterTypes[i]
1042: .isAssignableFrom(preConvArgs[i]
1043: .getClass()))) {
1044:
1045: ldcClassConstant(getWrapperClass(parameterTypes[i]));
1046:
1047: assert debug("INVOKESTATIC DataConversion.convert");
1048: mv
1049: .visitMethodInsn(INVOKESTATIC,
1050: "org/mvel/DataConversion",
1051: "convert",
1052: "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
1053:
1054: unwrapPrimitive(parameterTypes[i]);
1055: }
1056:
1057: else {
1058: unwrapPrimitive(parameterTypes[i]);
1059: }
1060:
1061: } else if (preConvArgs[i] == null
1062: || (parameterTypes[i] != String.class && !parameterTypes[i]
1063: .isAssignableFrom(preConvArgs[i]
1064: .getClass()))) {
1065:
1066: ldcClassConstant(parameterTypes[i]);
1067:
1068: assert debug("INVOKESTATIC DataConversion.convert");
1069: mv
1070: .visitMethodInsn(INVOKESTATIC,
1071: "org/mvel/DataConversion",
1072: "convert",
1073: "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
1074:
1075: assert debug("CHECKCAST "
1076: + getInternalName(parameterTypes[i]));
1077: mv.visitTypeInsn(CHECKCAST,
1078: getInternalName(parameterTypes[i]));
1079: } else if (parameterTypes[i] == String.class) {
1080: assert debug("<<<DYNAMIC TYPE OPTIMIZATION STRING>>");
1081: mv
1082: .visitMethodInsn(INVOKESTATIC,
1083: "java/lang/String", "valueOf",
1084: "(Ljava/lang/Object;)Ljava/lang/String;");
1085: } else {
1086: assert debug("<<<DYNAMIC TYPING BYPASS>>>");
1087: assert debug("<<<OPT. JUSTIFICATION "
1088: + parameterTypes[i] + "="
1089: + preConvArgs[i].getClass() + ">>>");
1090:
1091: assert debug("CHECKCAST "
1092: + getInternalName(parameterTypes[i]));
1093: mv.visitTypeInsn(CHECKCAST,
1094: getInternalName(parameterTypes[i]));
1095: }
1096:
1097: }
1098:
1099: if ((m.getModifiers() & Modifier.STATIC) != 0) {
1100: assert debug("INVOKESTATIC: " + m.getName());
1101: mv.visitMethodInsn(INVOKESTATIC, getInternalName(m
1102: .getDeclaringClass()), m.getName(),
1103: getMethodDescriptor(m));
1104: } else {
1105: if (m.getDeclaringClass() != cls
1106: && m.getDeclaringClass().isInterface()) {
1107: assert debug("INVOKEINTERFACE: "
1108: + getInternalName(m.getDeclaringClass())
1109: + "." + m.getName());
1110: mv.visitMethodInsn(INVOKEINTERFACE,
1111: getInternalName(m.getDeclaringClass()),
1112: m.getName(), getMethodDescriptor(m));
1113: } else {
1114: assert debug("INVOKEVIRTUAL: "
1115: + getInternalName(cls) + "."
1116: + m.getName());
1117: mv.visitMethodInsn(INVOKEVIRTUAL,
1118: getInternalName(cls), m.getName(),
1119: getMethodDescriptor(m));
1120: }
1121: }
1122:
1123: returnType = m.getReturnType();
1124:
1125: stacksize++;
1126: }
1127:
1128: return m.invoke(ctx, args);
1129: }
1130: }
1131:
1132: private void dataConversion(Class target) {
1133: ldcClassConstant(target);
1134: assert debug("INVOKESTATIC org/mvel/DataConversion.convert");
1135: mv
1136: .visitMethodInsn(INVOKESTATIC,
1137: "org/mvel/DataConversion", "convert",
1138: "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
1139: }
1140:
1141: private static final ClassLoader classLoader;
1142: private static final Method defineClass;
1143:
1144: static {
1145: try {
1146: classLoader = Thread.currentThread()
1147: .getContextClassLoader();
1148: //noinspection RedundantArrayCreation
1149: defineClass = ClassLoader.class.getDeclaredMethod(
1150: "defineClass", new Class[] { String.class,
1151: byte[].class, int.class, int.class });
1152: } catch (Exception e) {
1153: throw new RuntimeException(e);
1154: }
1155: }
1156:
1157: private java.lang.Class loadClass(String className, byte[] b)
1158: throws Exception {
1159: /**
1160: * This must be synchronized. Two classes cannot be simultaneously deployed in the JVM.
1161: */
1162: synchronized (defineClass) {
1163: defineClass.setAccessible(true);
1164: try {
1165: //noinspection RedundantArrayCreation
1166: return (Class) defineClass.invoke(classLoader,
1167: new Object[] { className, b, 0, (b.length) });
1168: } catch (Exception t) {
1169: dumpAdvancedDebugging();
1170: throw t;
1171: } finally {
1172: defineClass.setAccessible(false);
1173: }
1174: }
1175: }
1176:
1177: private boolean debug(String instruction) {
1178: // assert ParseTools.debug(instruction);
1179: if (buildLog != null) {
1180: buildLog.append(instruction).append("\n");
1181: }
1182: return true;
1183: }
1184:
1185: @SuppressWarnings({"SameReturnValue"})
1186: public String getName() {
1187: return "ASM";
1188: }
1189:
1190: public Object getResultOptPass() {
1191: return val;
1192: }
1193:
1194: private Class getWrapperClass(Class cls) {
1195: if (cls == boolean.class) {
1196: return Boolean.class;
1197: } else if (cls == int.class) {
1198: return Integer.class;
1199: } else if (cls == float.class) {
1200: return Float.class;
1201: } else if (cls == double.class) {
1202: return Double.class;
1203: } else if (cls == short.class) {
1204: return Short.class;
1205: } else if (cls == long.class) {
1206: return Long.class;
1207: } else if (cls == byte.class) {
1208: return Byte.class;
1209: } else if (cls == char.class) {
1210: return Character.class;
1211: }
1212:
1213: return null;
1214: }
1215:
1216: private void unwrapPrimitive(Class cls) {
1217: if (cls == boolean.class) {
1218: assert debug("CHECKCAST java/lang/Boolean");
1219: mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
1220: assert debug("INVOKEVIRTUAL java/lang/Boolean.booleanValue");
1221: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean",
1222: "booleanValue", "()Z");
1223: } else if (cls == int.class) {
1224: assert debug("CHECKCAST java/lang/Integer");
1225: mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
1226: assert debug("INVOKEVIRTUAL java/lang/Integer.intValue");
1227: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer",
1228: "intValue", "()I");
1229: } else if (cls == float.class) {
1230: assert debug("CHECKCAST java/lang/Float");
1231: mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
1232: assert debug("INVOKEVIRTUAL java/lang/Float.floatValue");
1233: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float",
1234: "floatValue", "()F");
1235: } else if (cls == double.class) {
1236: assert debug("CHECKCAST java/lang/Double");
1237: mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
1238: assert debug("INVOKEVIRTUAL java/lang/Double.doubleValue");
1239: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double",
1240: "doubleValue", "()D");
1241: } else if (cls == short.class) {
1242: assert debug("CHECKCAST java/lang/Short");
1243: mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
1244: assert debug("INVOKEVIRTUAL java/lang/Short.shortValue");
1245: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short",
1246: "shortValue", "()S");
1247: } else if (cls == long.class) {
1248: assert debug("CHECKCAST java/lang/Long");
1249: mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
1250: assert debug("INVOKEVIRTUAL java/lang/Long.longValue");
1251: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long",
1252: "longValue", "()J");
1253: } else if (cls == byte.class) {
1254: assert debug("CHECKCAST java/lang/Byte");
1255: mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
1256: assert debug("INVOKEVIRTUAL java/lang/Byte.byteValue");
1257: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte",
1258: "byteValue", "()B");
1259: } else if (cls == char.class) {
1260: assert debug("CHECKCAST java/lang/Character");
1261: mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
1262: assert debug("INVOKEVIRTUAL java/lang/Character.charValue");
1263: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character",
1264: "charValue", "()C");
1265: }
1266: }
1267:
1268: private void wrapPrimitive(Class<? extends Object> cls) {
1269: if (OPCODES_VERSION == Opcodes.V1_4) {
1270: /**
1271: * JAVA 1.4 SUCKS! DIE 1.4 DIE!!!
1272: */
1273:
1274: if (cls == boolean.class || cls == Boolean.class) {
1275: assert debug("NEW java/lang/Boolean");
1276: mv.visitTypeInsn(NEW, "java/lang/Boolean");
1277:
1278: assert debug("DUP X1");
1279: mv.visitInsn(DUP_X1);
1280:
1281: assert debug("SWAP");
1282: mv.visitInsn(SWAP);
1283:
1284: assert debug("INVOKESPECIAL java/lang/Boolan.<init>::(Z)V");
1285: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Boolean",
1286: "<init>", "(Z)V");
1287:
1288: returnType = Boolean.class;
1289: } else if (cls == int.class || cls == Integer.class) {
1290: assert debug("NEW java/lang/Integer");
1291: mv.visitTypeInsn(NEW, "java/lang/Integer");
1292:
1293: assert debug("DUP X1");
1294: mv.visitInsn(DUP_X1);
1295:
1296: assert debug("SWAP");
1297: mv.visitInsn(SWAP);
1298:
1299: assert debug("INVOKESPECIAL java/lang/Integer.<init>::(I)V");
1300: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer",
1301: "<init>", "(I)V");
1302:
1303: returnType = Integer.class;
1304: } else if (cls == float.class || cls == Float.class) {
1305: assert debug("NEW java/lang/Float");
1306: mv.visitTypeInsn(NEW, "java/lang/Float");
1307:
1308: assert debug("DUP X1");
1309: mv.visitInsn(DUP_X1);
1310:
1311: assert debug("SWAP");
1312: mv.visitInsn(SWAP);
1313:
1314: assert debug("INVOKESPECIAL java/lang/Float.<init>::(F)V");
1315: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Float",
1316: "<init>", "(F)V");
1317:
1318: returnType = Float.class;
1319: } else if (cls == double.class || cls == Double.class) {
1320: assert debug("NEW java/lang/Double");
1321: mv.visitTypeInsn(NEW, "java/lang/Double");
1322:
1323: assert debug("DUP X1");
1324: mv.visitInsn(DUP_X1);
1325:
1326: assert debug("SWAP");
1327: mv.visitInsn(SWAP);
1328:
1329: assert debug("INVOKESPECIAL java/lang/Double.<init>::(D)V");
1330: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Doble",
1331: "<init>", "(D)V");
1332:
1333: returnType = Double.class;
1334: } else if (cls == short.class || cls == Short.class) {
1335: assert debug("NEW java/lang/Short");
1336: mv.visitTypeInsn(NEW, "java/lang/Short");
1337:
1338: assert debug("DUP X1");
1339: mv.visitInsn(DUP_X1);
1340:
1341: assert debug("SWAP");
1342: mv.visitInsn(SWAP);
1343:
1344: assert debug("INVOKESPECIAL java/lang/Short.<init>::(S)V");
1345: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Short",
1346: "<init>", "(S)V");
1347:
1348: returnType = Short.class;
1349: } else if (cls == long.class || cls == Long.class) {
1350: assert debug("NEW java/lang/Long");
1351: mv.visitTypeInsn(NEW, "java/lang/Long");
1352:
1353: assert debug("DUP X1");
1354: mv.visitInsn(DUP_X1);
1355:
1356: assert debug("SWAP");
1357: mv.visitInsn(SWAP);
1358:
1359: assert debug("INVOKESPECIAL java/lang/Long.<init>::(L)V");
1360: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Float",
1361: "<init>", "(L)V");
1362:
1363: returnType = Long.class;
1364: } else if (cls == byte.class || cls == Byte.class) {
1365: assert debug("NEW java/lang/Byte");
1366: mv.visitTypeInsn(NEW, "java/lang/Byte");
1367:
1368: assert debug("DUP X1");
1369: mv.visitInsn(DUP_X1);
1370:
1371: assert debug("SWAP");
1372: mv.visitInsn(SWAP);
1373:
1374: assert debug("INVOKESPECIAL java/lang/Byte.<init>::(B)V");
1375: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Byte",
1376: "<init>", "(B)V");
1377:
1378: returnType = Byte.class;
1379: } else if (cls == char.class || cls == Character.class) {
1380: assert debug("NEW java/lang/Character");
1381: mv.visitTypeInsn(NEW, "java/lang/Character");
1382:
1383: assert debug("DUP X1");
1384: mv.visitInsn(DUP_X1);
1385:
1386: assert debug("SWAP");
1387: mv.visitInsn(SWAP);
1388:
1389: assert debug("INVOKESPECIAL java/lang/Character.<init>::(C)V");
1390: mv.visitMethodInsn(INVOKESPECIAL,
1391: "java/lang/Character", "<init>", "(C)V");
1392:
1393: returnType = Character.class;
1394: }
1395: } else {
1396: if (cls == boolean.class || cls == Boolean.class) {
1397: assert debug("INVOKESTATIC java/lang/Boolean.valueOf");
1398: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean",
1399: "valueOf", "(Z)Ljava/lang/Boolean;");
1400: returnType = Boolean.class;
1401: } else if (cls == int.class || cls == Integer.class) {
1402: assert debug("INVOKESTATIC java/lang/Integer.valueOf");
1403: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer",
1404: "valueOf", "(I)Ljava/lang/Integer;");
1405: returnType = Integer.class;
1406: } else if (cls == float.class || cls == Float.class) {
1407: assert debug("INVOKESTATIC java/lang/Float.valueOf");
1408: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float",
1409: "valueOf", "(F)Ljava/lang/Float;");
1410: returnType = Float.class;
1411: } else if (cls == double.class || cls == Double.class) {
1412: assert debug("INVOKESTATIC java/lang/Double.valueOf");
1413: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double",
1414: "valueOf", "(D)Ljava/lang/Double;");
1415: returnType = Double.class;
1416: } else if (cls == short.class || cls == Short.class) {
1417: assert debug("INVOKESTATIC java/lang/Short.valueOf");
1418: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short",
1419: "valueOf", "(S)Ljava/lang/Short;");
1420: returnType = Short.class;
1421: } else if (cls == long.class || cls == Long.class) {
1422: assert debug("INVOKESTATIC java/lang/Long.valueOf");
1423: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long",
1424: "valueOf", "(J)Ljava/lang/Long;");
1425: returnType = Long.class;
1426: } else if (cls == byte.class || cls == Byte.class) {
1427: assert debug("INVOKESTATIC java/lang/Byte.valueOf");
1428: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte",
1429: "valueOf", "(B)Ljava/lang/Byte;");
1430: returnType = Byte.class;
1431: } else if (cls == char.class || cls == Character.class) {
1432: assert debug("INVOKESTATIC java/lang/Character.valueOf");
1433: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character",
1434: "valueOf", "(C)Ljava/lang/Character;");
1435: returnType = Character.class;
1436: }
1437: }
1438: }
1439:
1440: private void anyArrayCheck(Class<? extends Object> cls) {
1441: if (cls == boolean[].class) {
1442: assert debug("CHECKCAST [Z");
1443: mv.visitTypeInsn(CHECKCAST, "[Z");
1444: } else if (cls == int[].class) {
1445: assert debug("CHECKCAST [I");
1446: mv.visitTypeInsn(CHECKCAST, "[I");
1447: } else if (cls == float[].class) {
1448: assert debug("CHECKCAST [F");
1449: mv.visitTypeInsn(CHECKCAST, "[F");
1450: } else if (cls == double[].class) {
1451: assert debug("CHECKCAST [D");
1452: mv.visitTypeInsn(CHECKCAST, "[D");
1453: } else if (cls == short[].class) {
1454: assert debug("CHECKCAST [S");
1455: mv.visitTypeInsn(CHECKCAST, "[S");
1456: } else if (cls == long[].class) {
1457: assert debug("CHECKCAST [J");
1458: mv.visitTypeInsn(CHECKCAST, "[J");
1459: } else if (cls == byte[].class) {
1460: assert debug("CHECKCAST [B");
1461: mv.visitTypeInsn(CHECKCAST, "[B");
1462: } else if (cls == char[].class) {
1463: assert debug("CHECKCAST [C");
1464: mv.visitTypeInsn(CHECKCAST, "[C");
1465: } else {
1466: assert debug("CHECKCAST [Ljava/lang/Object;");
1467: mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
1468: }
1469: }
1470:
1471: private void writeOutLiteralWrapped(Object lit) {
1472: if (lit instanceof Integer) {
1473: intPush((Integer) lit);
1474: wrapPrimitive(int.class);
1475: return;
1476: }
1477:
1478: assert debug("LDC " + lit);
1479: if (lit instanceof String) {
1480: mv.visitLdcInsn(lit);
1481: } else if (lit instanceof Long) {
1482: mv.visitLdcInsn(lit);
1483: wrapPrimitive(long.class);
1484: } else if (lit instanceof Float) {
1485: mv.visitLdcInsn(lit);
1486: wrapPrimitive(float.class);
1487: } else if (lit instanceof Double) {
1488: mv.visitLdcInsn(lit);
1489: wrapPrimitive(double.class);
1490: } else if (lit instanceof Short) {
1491: mv.visitLdcInsn(lit);
1492: wrapPrimitive(short.class);
1493: } else if (lit instanceof Character) {
1494: mv.visitLdcInsn(lit);
1495: wrapPrimitive(char.class);
1496: } else if (lit instanceof Boolean) {
1497: mv.visitLdcInsn(lit);
1498: wrapPrimitive(boolean.class);
1499: } else if (lit instanceof Byte) {
1500: mv.visitLdcInsn(lit);
1501: wrapPrimitive(byte.class);
1502: }
1503: }
1504:
1505: private void loadVariableByName(String name) {
1506: assert debug("ALOAD 3");
1507: mv.visitVarInsn(ALOAD, 3);
1508:
1509: assert debug("LDC :" + name);
1510: mv.visitLdcInsn(name);
1511:
1512: assert debug("INVOKEINTERFACE org/mvel/integration/VariableResolverFactory.getVariableResolver");
1513: mv
1514: .visitMethodInsn(INVOKEINTERFACE,
1515: "org/mvel/integration/VariableResolverFactory",
1516: "getVariableResolver",
1517: "(Ljava/lang/String;)Lorg/mvel/integration/VariableResolver;");
1518:
1519: assert debug("INVOKEINTERFACE org/mvel/integration/VariableResolver.getValue");
1520: mv.visitMethodInsn(INVOKEINTERFACE,
1521: "org/mvel/integration/VariableResolver", "getValue",
1522: "()Ljava/lang/Object;");
1523:
1524: returnType = Object.class;
1525: }
1526:
1527: private void loadVariableByIndex(int pos) {
1528: assert debug("ALOAD 3");
1529: mv.visitVarInsn(ALOAD, 3);
1530:
1531: assert debug("PUSH IDX VAL =" + pos);
1532: intPush(pos);
1533:
1534: assert debug("INVOKEINTERFACE org/mvel/integration/VariableResolverFactory.getIndexedVariableResolver");
1535: mv.visitMethodInsn(INVOKEINTERFACE,
1536: "org/mvel/integration/VariableResolverFactory",
1537: "getIndexedVariableResolver",
1538: "(I)Lorg/mvel/integration/VariableResolver;");
1539:
1540: assert debug("INVOKEINTERFACE org/mvel/integration/VariableResolver.getValue");
1541: mv.visitMethodInsn(INVOKEINTERFACE,
1542: "org/mvel/integration/VariableResolver", "getValue",
1543: "()Ljava/lang/Object;");
1544:
1545: returnType = Object.class;
1546: }
1547:
1548: private void loadField(int number) {
1549: assert debug("ALOAD 0");
1550: mv.visitVarInsn(ALOAD, 0);
1551:
1552: assert debug("GETFIELD p" + number);
1553: mv.visitFieldInsn(GETFIELD, className, "p" + number,
1554: "Lorg/mvel/compiler/ExecutableStatement;");
1555: }
1556:
1557: // private void writeOutLiteral(Object lit) {
1558: // if (lit instanceof Integer) {
1559: // intPush((Integer) lit);
1560: // return;
1561: // }
1562: //
1563: //
1564: // debug("LDC " + lit);
1565: // if (lit instanceof String) {
1566: // mv.visitLdcInsn(lit);
1567: // }
1568: // else if (lit instanceof Long) {
1569: // mv.visitLdcInsn(lit);
1570: // }
1571: // else if (lit instanceof Float) {
1572: // mv.visitLdcInsn(lit);
1573: // }
1574: // else if (lit instanceof Double) {
1575: // mv.visitLdcInsn(lit);
1576: // }
1577: // else if (lit instanceof Short) {
1578: // mv.visitLdcInsn(lit);
1579: // }
1580: // else if (lit instanceof Character) {
1581: // mv.visitLdcInsn(lit);
1582: // }
1583: // else if (lit instanceof Boolean) {
1584: // mv.visitLdcInsn(lit);
1585: // }
1586: // else if (lit instanceof Byte) {
1587: // mv.visitLdcInsn(lit);
1588: // }
1589: // }
1590:
1591: private void ldcClassConstant(Class cls) {
1592: if (OPCODES_VERSION == Opcodes.V1_4) {
1593: assert debug("LDC \"" + cls.getName() + "\"");
1594: mv.visitLdcInsn(cls.getName());
1595: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class",
1596: "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
1597: Label l4 = new Label();
1598: mv.visitJumpInsn(GOTO, l4);
1599: mv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
1600: mv.visitInsn(DUP_X1);
1601: mv.visitInsn(SWAP);
1602: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable",
1603: "getMessage", "()Ljava/lang/String;");
1604: mv.visitMethodInsn(INVOKESPECIAL,
1605: "java/lang/NoClassDefFoundError", "<init>",
1606: "(Ljava/lang/String;)V");
1607: mv.visitInsn(ATHROW);
1608: mv.visitLabel(l4);
1609:
1610: } else {
1611: assert debug("LDC " + getType(cls));
1612: mv.visitLdcInsn(getType(cls));
1613: }
1614: }
1615:
1616: private void buildInputs() {
1617: if (compiledInputs.size() == 0)
1618: return;
1619:
1620: assert debug("\n{SETTING UP MEMBERS...}\n");
1621:
1622: StringAppender constSig = new StringAppender("(");
1623: int size = compiledInputs.size();
1624:
1625: for (int i = 0; i < size; i++) {
1626: assert debug("ACC_PRIVATE p" + i);
1627: //FieldVisitor fv =
1628: cw.visitField(ACC_PRIVATE, "p" + i,
1629: "Lorg/mvel/compiler/ExecutableStatement;", null,
1630: null).visitEnd();
1631: // fv.visitEnd();
1632:
1633: constSig.append("Lorg/mvel/compiler/ExecutableStatement;");
1634: }
1635: constSig.append(")V");
1636:
1637: assert debug("\n{CREATING INJECTION CONSTRUCTOR}\n");
1638:
1639: MethodVisitor cv = cw.visitMethod(ACC_PUBLIC, "<init>",
1640: constSig.toString(), null, null);
1641: cv.visitCode();
1642: assert debug("ALOAD 0");
1643: cv.visitVarInsn(ALOAD, 0);
1644: assert debug("INVOKESPECIAL java/lang/Object.<init>");
1645: cv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>",
1646: "()V");
1647:
1648: for (int i = 0; i < size; i++) {
1649: assert debug("ALOAD 0");
1650: cv.visitVarInsn(ALOAD, 0);
1651: assert debug("ALOAD " + (i + 1));
1652: cv.visitVarInsn(ALOAD, i + 1);
1653: assert debug("PUTFIELD p" + i);
1654: cv.visitFieldInsn(PUTFIELD, className, "p" + i,
1655: "Lorg/mvel/compiler/ExecutableStatement;");
1656: }
1657:
1658: assert debug("RETURN");
1659: cv.visitInsn(RETURN);
1660: cv.visitMaxs(0, 0);
1661: cv.visitEnd();
1662:
1663: assert debug("}");
1664: }
1665:
1666: private static final int ARRAY = 0;
1667: private static final int LIST = 1;
1668: private static final int MAP = 2;
1669: private static final int VAL = 3;
1670:
1671: private int _getAccessor(Object o) {
1672: if (o instanceof List) {
1673: assert debug("NEW " + LIST_IMPL);
1674: mv.visitTypeInsn(NEW, LIST_IMPL);
1675:
1676: assert debug("DUP");
1677: mv.visitInsn(DUP);
1678:
1679: assert debug("DUP");
1680: mv.visitInsn(DUP);
1681:
1682: intPush(((List) o).size());
1683: assert debug("INVOKESPECIAL " + LIST_IMPL + ".<init>");
1684: mv.visitMethodInsn(INVOKESPECIAL, LIST_IMPL, "<init>",
1685: "(I)V");
1686:
1687: for (Object item : (List) o) {
1688: if (_getAccessor(item) != VAL) {
1689: assert debug("POP");
1690: mv.visitInsn(POP);
1691: }
1692:
1693: assert debug("INVOKEINTERFACE java/util/List.add");
1694: mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List",
1695: "add", "(Ljava/lang/Object;)Z");
1696:
1697: assert debug("POP");
1698: mv.visitInsn(POP);
1699:
1700: assert debug("DUP");
1701: mv.visitInsn(DUP);
1702: }
1703:
1704: return LIST;
1705: } else if (o instanceof Map) {
1706: assert debug("NEW " + MAP_IMPL);
1707: mv.visitTypeInsn(NEW, MAP_IMPL);
1708:
1709: assert debug("DUP");
1710: mv.visitInsn(DUP);
1711:
1712: assert debug("DUP");
1713: mv.visitInsn(DUP);
1714:
1715: intPush(((Map) o).size());
1716:
1717: assert debug("INVOKESPECIAL " + MAP_IMPL + ".<init>");
1718: mv.visitMethodInsn(INVOKESPECIAL, MAP_IMPL, "<init>",
1719: "(I)V");
1720:
1721: for (Object item : ((Map) o).keySet()) {
1722: mv.visitTypeInsn(CHECKCAST, "java/util/Map");
1723:
1724: if (_getAccessor(item) != VAL) {
1725: assert debug("POP");
1726: mv.visitInsn(POP);
1727: }
1728: if (_getAccessor(((Map) o).get(item)) != VAL) {
1729: assert debug("POP");
1730: mv.visitInsn(POP);
1731: }
1732:
1733: assert debug("INVOKEINTERFACE java/util/Map.put");
1734: mv
1735: .visitMethodInsn(INVOKEINTERFACE,
1736: "java/util/Map", "put",
1737: "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
1738:
1739: assert debug("POP");
1740: mv.visitInsn(POP);
1741:
1742: assert debug("DUP");
1743: mv.visitInsn(DUP);
1744: }
1745:
1746: return MAP;
1747: } else if (o instanceof Object[]) {
1748: intPush(((Object[]) o).length);
1749:
1750: assert debug("ANEWARRAY (" + o.hashCode() + ")");
1751: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
1752:
1753: assert debug("DUP");
1754: mv.visitInsn(DUP);
1755:
1756: int i = 0;
1757: for (Object item : (Object[]) o) {
1758: intPush(i);
1759:
1760: if (_getAccessor(item) != VAL) {
1761: assert debug("POP");
1762: mv.visitInsn(POP);
1763: }
1764:
1765: assert debug("AASTORE (" + o.hashCode() + ")");
1766: mv.visitInsn(AASTORE);
1767:
1768: assert debug("DUP");
1769: mv.visitInsn(DUP);
1770:
1771: i++;
1772: }
1773:
1774: return ARRAY;
1775: } else {
1776: writeLiteralOrSubexpression(subCompileExpression((String) o));
1777: return VAL;
1778: }
1779: }
1780:
1781: private Class writeLiteralOrSubexpression(Object stmt) {
1782: return writeLiteralOrSubexpression(stmt, null, null);
1783: }
1784:
1785: private Class writeLiteralOrSubexpression(Object stmt,
1786: Class desiredTarget) {
1787: return writeLiteralOrSubexpression(stmt, desiredTarget, null);
1788: }
1789:
1790: private Class writeLiteralOrSubexpression(Object stmt,
1791: Class desiredTarget, Class knownIngressType) {
1792:
1793: if (stmt instanceof ExecutableLiteral) {
1794: Class type = ((ExecutableLiteral) stmt).getLiteral()
1795: .getClass();
1796:
1797: assert debug("*** type:" + type + ";desired:"
1798: + desiredTarget);
1799:
1800: if (type == Integer.class && desiredTarget == int.class) {
1801: intPush(((ExecutableLiteral) stmt).getInteger32());
1802: type = int.class;
1803: } else if (desiredTarget != null && type != desiredTarget) {
1804: assert debug("*** Converting because desiredType("
1805: + desiredTarget.getClass() + ") is not: "
1806: + type);
1807:
1808: dataConversion(desiredTarget);
1809: writeOutLiteralWrapped(convert(
1810: ((ExecutableLiteral) stmt).getLiteral(),
1811: desiredTarget));
1812: } else {
1813: writeOutLiteralWrapped(((ExecutableLiteral) stmt)
1814: .getLiteral());
1815: }
1816:
1817: return type;
1818: } else {
1819: literal = false;
1820:
1821: compiledInputs.add((ExecutableStatement) stmt);
1822:
1823: assert debug("ALOAD 0");
1824: mv.visitVarInsn(ALOAD, 0);
1825:
1826: assert debug("GETFIELD p" + (compiledInputs.size() - 1));
1827: mv.visitFieldInsn(GETFIELD, className, "p"
1828: + (compiledInputs.size() - 1),
1829: "Lorg/mvel/compiler/ExecutableStatement;");
1830:
1831: assert debug("ALOAD 2");
1832: mv.visitVarInsn(ALOAD, 2);
1833:
1834: assert debug("ALOAD 3");
1835: mv.visitVarInsn(ALOAD, 3);
1836:
1837: assert debug("INVOKEINTERFACE ExecutableStatement.getValue");
1838: mv
1839: .visitMethodInsn(
1840: INVOKEINTERFACE,
1841: getInternalName(ExecutableStatement.class),
1842: "getValue",
1843: "(Ljava/lang/Object;Lorg/mvel/integration/VariableResolverFactory;)Ljava/lang/Object;");
1844:
1845: Class type;
1846: if (knownIngressType == null) {
1847: type = ((ExecutableStatement) stmt)
1848: .getKnownEgressType();
1849: } else {
1850: type = knownIngressType;
1851: }
1852:
1853: if (desiredTarget != null && type != desiredTarget) {
1854: // dataConversion(desiredTarget);
1855: if (desiredTarget.isPrimitive()) {
1856: if (type == null)
1857: throw new OptimizationFailure(
1858: "cannot optimize expression: "
1859: + new String(expr)
1860: + ": cannot determine ingress type for primitive output");
1861:
1862: checkcast(type);
1863: unwrapPrimitive(desiredTarget);
1864: }
1865: }
1866:
1867: return type;
1868: }
1869:
1870: }
1871:
1872: private void addPrintOut(String text) {
1873: mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
1874: "Ljava/io/PrintStream;");
1875: mv.visitLdcInsn(text);
1876: mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream",
1877: "println", "(Ljava/lang/String;)V");
1878: }
1879:
1880: public Accessor optimizeCollection(char[] property, Object ctx,
1881: Object this Ref, VariableResolverFactory factory) {
1882: this .cursor = 0;
1883: this .length = (this .expr = property).length;
1884: this .compiledInputs = new ArrayList<ExecutableStatement>();
1885:
1886: this .ctx = ctx;
1887: this .this Ref = this Ref;
1888: this .variableFactory = factory;
1889:
1890: CollectionParser parser = new CollectionParser();
1891: Object o = ((List) parser.parseCollection(property)).get(0);
1892:
1893: _initJIT();
1894:
1895: literal = true;
1896:
1897: switch (_getAccessor(o)) {
1898: case LIST:
1899: this .returnType = List.class;
1900: break;
1901: case MAP:
1902: this .returnType = Map.class;
1903: break;
1904: case ARRAY:
1905: this .returnType = Object[].class;
1906: break;
1907: }
1908:
1909: _finishJIT();
1910:
1911: int end = parser.getCursor() + 2;
1912: try {
1913: Accessor compiledAccessor = _initializeAccessor();
1914:
1915: if (end < property.length) {
1916: return new Union(compiledAccessor,
1917: subset(property, end));
1918: } else {
1919: return compiledAccessor;
1920: }
1921:
1922: } catch (Exception e) {
1923: throw new OptimizationFailure(
1924: "could not optimize collection", e);
1925: }
1926: }
1927:
1928: private void checkcast(Class cls) {
1929: assert debug("CHECKCAST " + getInternalName(cls));
1930: mv.visitTypeInsn(CHECKCAST, getInternalName(cls));
1931: }
1932:
1933: private void intPush(int index) {
1934: if (index < 6) {
1935: switch (index) {
1936: case 0:
1937: assert debug("ICONST_0");
1938: mv.visitInsn(ICONST_0);
1939: break;
1940: case 1:
1941: assert debug("ICONST_1");
1942: mv.visitInsn(ICONST_1);
1943: break;
1944: case 2:
1945: assert debug("ICONST_2");
1946: mv.visitInsn(ICONST_2);
1947: break;
1948: case 3:
1949: assert debug("ICONST_3");
1950: mv.visitInsn(ICONST_3);
1951: break;
1952: case 4:
1953: assert debug("ICONST_4");
1954: mv.visitInsn(ICONST_4);
1955: break;
1956: case 5:
1957: assert debug("ICONST_5");
1958: mv.visitInsn(ICONST_5);
1959: break;
1960: }
1961: } else if (index < Byte.MAX_VALUE) {
1962: assert debug("BIPUSH " + index);
1963: mv.visitIntInsn(BIPUSH, index);
1964: } else {
1965: assert debug("SIPUSH " + index);
1966: mv.visitIntInsn(SIPUSH, index);
1967: }
1968: }
1969:
1970: public Accessor optimizeObjectCreation(char[] property, Object ctx,
1971: Object this Ref, VariableResolverFactory factory) {
1972: _initJIT();
1973:
1974: compiledInputs = new ArrayList<ExecutableStatement>();
1975: this .length = (this .expr = property).length;
1976: this .ctx = ctx;
1977: this .this Ref = this Ref;
1978: this .variableFactory = factory;
1979:
1980: String[] cnsRes = captureContructorAndResidual(property);
1981: String[] constructorParms = parseMethodOrConstructor(cnsRes[0]
1982: .toCharArray());
1983:
1984: try {
1985: if (constructorParms != null) {
1986: for (String constructorParm : constructorParms) {
1987: compiledInputs
1988: .add((ExecutableStatement) subCompileExpression(constructorParm));
1989: }
1990:
1991: Class cls = findClass(factory, new String(subset(
1992: property, 0, findFirst('(', property))));
1993:
1994: assert debug("NEW " + getInternalName(cls));
1995: mv.visitTypeInsn(NEW, getInternalName(cls));
1996: assert debug("DUP");
1997: mv.visitInsn(DUP);
1998:
1999: Object[] parms = new Object[constructorParms.length];
2000:
2001: int i = 0;
2002: for (ExecutableStatement es : compiledInputs) {
2003: parms[i++] = es.getValue(ctx, factory);
2004: }
2005:
2006: Constructor cns = getBestConstructorCanadidate(parms,
2007: cls);
2008:
2009: if (cns == null)
2010: throw new CompileException(
2011: "unable to find constructor for: "
2012: + cls.getName());
2013:
2014: Class tg;
2015: for (i = 0; i < constructorParms.length; i++) {
2016: assert debug("ALOAD 0");
2017: mv.visitVarInsn(ALOAD, 0);
2018: assert debug("GETFIELD p" + i);
2019: mv.visitFieldInsn(GETFIELD, className, "p" + i,
2020: "Lorg/mvel/compiler/ExecutableStatement;");
2021: assert debug("ALOAD 2");
2022: mv.visitVarInsn(ALOAD, 2);
2023: assert debug("ALOAD 3");
2024: mv.visitVarInsn(ALOAD, 3);
2025: assert debug("INVOKEINTERFACE org/mvel/compiler/ExecutableStatement.getValue");
2026: mv
2027: .visitMethodInsn(
2028: INVOKEINTERFACE,
2029: "org/mvel/compiler/ExecutableStatement",
2030: "getValue",
2031: "(Ljava/lang/Object;Lorg/mvel/integration/VariableResolverFactory;)Ljava/lang/Object;");
2032:
2033: tg = cns.getParameterTypes()[i].isPrimitive() ? getWrapperClass(cns
2034: .getParameterTypes()[i])
2035: : cns.getParameterTypes()[i];
2036:
2037: if (parms[i] != null
2038: && !parms[i].getClass().isAssignableFrom(
2039: cns.getParameterTypes()[i])) {
2040: ldcClassConstant(tg);
2041:
2042: assert debug("INVOKESTATIC org/mvel/DataConversion.convert");
2043: mv
2044: .visitMethodInsn(INVOKESTATIC,
2045: "org/mvel/DataConversion",
2046: "convert",
2047: "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
2048:
2049: if (cns.getParameterTypes()[i].isPrimitive()) {
2050: unwrapPrimitive(cns.getParameterTypes()[i]);
2051: } else {
2052: assert debug("CHECKCAST "
2053: + getInternalName(tg));
2054: mv.visitTypeInsn(CHECKCAST,
2055: getInternalName(tg));
2056: }
2057:
2058: } else {
2059: assert debug("CHECKCAST "
2060: + getInternalName(cns
2061: .getParameterTypes()[i]));
2062: mv.visitTypeInsn(CHECKCAST, getInternalName(cns
2063: .getParameterTypes()[i]));
2064: }
2065:
2066: }
2067:
2068: assert debug("INVOKESPECIAL " + getInternalName(cls)
2069: + ".<init> : " + getConstructorDescriptor(cns));
2070: mv.visitMethodInsn(INVOKESPECIAL, getInternalName(cls),
2071: "<init>", getConstructorDescriptor(cns));
2072:
2073: _finishJIT();
2074:
2075: Accessor acc = _initializeAccessor();
2076:
2077: if (cnsRes.length > 1 && cnsRes[1] != null
2078: && !cnsRes[1].trim().equals("")) {
2079: return new Union(acc, cnsRes[1].toCharArray());
2080: }
2081:
2082: return acc;
2083: } else {
2084: Class cls = findClass(factory, new String(property));
2085:
2086: assert debug("NEW " + getInternalName(cls));
2087: mv.visitTypeInsn(NEW, getInternalName(cls));
2088: assert debug("DUP");
2089: mv.visitInsn(DUP);
2090:
2091: Constructor cns = cls.getConstructor(EMPTYCLS);
2092:
2093: assert debug("INVOKESPECIAL <init>");
2094:
2095: mv.visitMethodInsn(INVOKESPECIAL, getInternalName(cls),
2096: "<init>", getConstructorDescriptor(cns));
2097:
2098: _finishJIT();
2099: Accessor acc = _initializeAccessor();
2100:
2101: if (cnsRes.length > 1 && cnsRes[1] != null
2102: && !cnsRes[1].trim().equals("")) {
2103: return new Union(acc, cnsRes[1].toCharArray());
2104: }
2105:
2106: return acc;
2107: }
2108: } catch (ClassNotFoundException e) {
2109: throw new CompileException(
2110: "class or class reference not found: "
2111: + new String(property));
2112: } catch (Exception e) {
2113: throw new OptimizationFailure(
2114: "could not optimize construtor: "
2115: + new String(property), e);
2116: }
2117: }
2118:
2119: public Accessor optimizeFold(char[] property, Object ctx,
2120: Object this Ref, VariableResolverFactory factory) {
2121: throw new OptimizationNotSupported(
2122: "JIT does not yet support fold operations.");
2123: }
2124:
2125: public Class getEgressType() {
2126: return returnType;
2127: }
2128:
2129: private void dumpAdvancedDebugging() {
2130: if (buildLog == null)
2131: return;
2132:
2133: System.out.println("JIT Compiler Dump for: <<"
2134: + new String(expr)
2135: + ">>\n-------------------------------\n");
2136: System.out.println(buildLog.toString());
2137: System.out.println("\n<END OF DUMP>\n");
2138: if (MVEL.isFileDebugging()) {
2139: try {
2140: FileWriter writer = ParseTools.getDebugFileWriter();
2141: writer.write(buildLog.toString());
2142: writer.flush();
2143: writer.close();
2144: } catch (IOException e) {
2145: // --
2146: }
2147: }
2148: }
2149:
2150: public boolean isLiteralOnly() {
2151: return literal;
2152: }
2153: }
|