/src/main/java/org/mvel2/optimizers/impl/asm/ASMAccessorOptimizer.java
Java | 3277 lines | 2572 code | 625 blank | 80 comment | 809 complexity | c886c878341763bdc0501522fd4737f4 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0
Large files files are truncated, but you can click here to view the full file
- /**
- * MVEL 2.0
- * Copyright (C) 2007 The Codehaus
- * Mike Brock, Dhanji Prasanna, John Graham, Mark Proctor
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.mvel2.optimizers.impl.asm;
- import org.mvel2.*;
- import org.mvel2.asm.ClassWriter;
- import org.mvel2.asm.Label;
- import org.mvel2.asm.MethodVisitor;
- import org.mvel2.asm.Opcodes;
- import org.mvel2.ast.*;
- import org.mvel2.compiler.*;
- import org.mvel2.integration.GlobalListenerFactory;
- import org.mvel2.integration.PropertyHandler;
- import org.mvel2.integration.VariableResolverFactory;
- import org.mvel2.optimizers.AbstractOptimizer;
- import org.mvel2.optimizers.AccessorOptimizer;
- import org.mvel2.optimizers.OptimizationNotSupported;
- import org.mvel2.optimizers.impl.refl.nodes.Union;
- import org.mvel2.util.*;
- import java.io.FileWriter;
- import java.io.IOException;
- import java.lang.reflect.*;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Map;
- import static java.lang.String.valueOf;
- import static java.lang.System.getProperty;
- import static java.lang.Thread.currentThread;
- import static java.lang.reflect.Array.getLength;
- import static java.lang.reflect.Modifier.FINAL;
- import static java.lang.reflect.Modifier.STATIC;
- import static org.mvel2.DataConversion.canConvert;
- import static org.mvel2.DataConversion.convert;
- import static org.mvel2.MVEL.eval;
- import static org.mvel2.MVEL.isAdvancedDebugging;
- import static org.mvel2.asm.Opcodes.*;
- import static org.mvel2.asm.Type.*;
- import static org.mvel2.ast.TypeDescriptor.getClassReference;
- import static org.mvel2.integration.GlobalListenerFactory.hasGetListeners;
- import static org.mvel2.integration.GlobalListenerFactory.notifyGetListeners;
- import static org.mvel2.integration.PropertyHandlerFactory.*;
- import static org.mvel2.util.ArrayTools.findFirst;
- import static org.mvel2.util.ParseTools.*;
- import static org.mvel2.util.PropertyTools.getFieldOrAccessor;
- import static org.mvel2.util.PropertyTools.getFieldOrWriteAccessor;
- import static org.mvel2.util.ReflectionUtil.toNonPrimitiveArray;
- import static org.mvel2.util.ReflectionUtil.toNonPrimitiveType;
- import static org.mvel2.util.Varargs.*;
- /**
- * Implementation of the MVEL Just-in-Time (JIT) compiler for Property Accessors using the ASM bytecode
- * engineering library.
- * <p/>
- */
- @SuppressWarnings({"TypeParameterExplicitlyExtendsObject", "unchecked", "UnusedDeclaration"})
- public class ASMAccessorOptimizer extends AbstractOptimizer implements AccessorOptimizer {
- private static final String MAP_IMPL = "java/util/HashMap";
- private static String LIST_IMPL;
- private static String NAMESPACE;
- private static final int OPCODES_VERSION;
- static {
- final String javaVersion = getProperty("java.version");
- if (javaVersion.startsWith("1.4"))
- OPCODES_VERSION = Opcodes.V1_4;
- else if (javaVersion.startsWith("1.5"))
- OPCODES_VERSION = Opcodes.V1_5;
- else if (javaVersion.startsWith("1.6") || javaVersion.startsWith("1.7"))
- OPCODES_VERSION = Opcodes.V1_6;
- else
- OPCODES_VERSION = Opcodes.V1_2;
- String defaultNameSapce = getProperty("mvel2.namespace");
- if (defaultNameSapce == null) NAMESPACE = "org/mvel2/";
- else NAMESPACE = defaultNameSapce;
- String jitListImpl = getProperty("mvel2.jit.list_impl");
- if (jitListImpl == null) LIST_IMPL = NAMESPACE + "util/FastList";
- else LIST_IMPL = jitListImpl;
- }
- private Object ctx;
- private Object thisRef;
- private VariableResolverFactory variableFactory;
- private static final Object[] EMPTYARG = new Object[0];
- private static final Class[] EMPTYCLS = new Class[0];
- private boolean first = true;
- private boolean noinit = false;
- private boolean deferFinish = false;
- private boolean literal = false;
- private boolean propNull = false;
- private boolean methNull = false;
- private String className;
- private ClassWriter cw;
- private MethodVisitor mv;
- private Object val;
- private int stacksize = 1;
- private int maxlocals = 1;
- private long time;
- private ArrayList<ExecutableStatement> compiledInputs;
- private Class ingressType;
- private Class returnType;
- private int compileDepth = 0;
- @SuppressWarnings({"StringBufferField"})
- private StringAppender buildLog;
- public ASMAccessorOptimizer() {
- //do this to confirm we're running the correct version
- //otherwise should create a verification error in VM
- new ClassWriter(ClassWriter.COMPUTE_MAXS);
- }
- private ASMAccessorOptimizer(ClassWriter cw, MethodVisitor mv,
- ArrayList<ExecutableStatement> compiledInputs, String className,
- StringAppender buildLog, int compileDepth) {
- this.cw = cw;
- this.mv = mv;
- this.compiledInputs = compiledInputs;
- this.className = className;
- this.buildLog = buildLog;
- this.compileDepth = compileDepth + 1;
- noinit = true;
- deferFinish = true;
- }
- /**
- * Does all the boilerplate for initiating the JIT.
- */
- private void _initJIT() {
- if (isAdvancedDebugging()) {
- buildLog = new StringAppender();
- }
- cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
- synchronized (Runtime.getRuntime()) {
- cw.visit(OPCODES_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, className = "ASMAccessorImpl_"
- + valueOf(cw.hashCode()).replaceAll("\\-", "_") + (System.currentTimeMillis() / 10) +
- ((int) Math.random() * 100),
- null, "java/lang/Object", new String[]{NAMESPACE + "compiler/Accessor"});
- }
- MethodVisitor m = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
- m.visitCode();
- m.visitVarInsn(Opcodes.ALOAD, 0);
- m.visitMethodInsn(INVOKESPECIAL, "java/lang/Object",
- "<init>", "()V");
- m.visitInsn(RETURN);
- m.visitMaxs(1, 1);
- m.visitEnd();
- (mv = cw.visitMethod(ACC_PUBLIC, "getValue",
- "(Ljava/lang/Object;Ljava/lang/Object;L" + NAMESPACE
- + "integration/VariableResolverFactory;)Ljava/lang/Object;", null, null)).visitCode();
- }
- private void _initJIT2() {
- if (isAdvancedDebugging()) {
- buildLog = new StringAppender();
- }
- cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
- synchronized (Runtime.getRuntime()) {
- cw.visit(OPCODES_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, className = "ASMAccessorImpl_"
- + valueOf(cw.hashCode()).replaceAll("\\-", "_") + (System.currentTimeMillis() / 10) +
- ((int) Math.random() * 100),
- null, "java/lang/Object", new String[]{NAMESPACE + "compiler/Accessor"});
- }
- MethodVisitor m = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
- m.visitCode();
- m.visitVarInsn(Opcodes.ALOAD, 0);
- m.visitMethodInsn(INVOKESPECIAL, "java/lang/Object",
- "<init>", "()V");
- m.visitInsn(RETURN);
- m.visitMaxs(1, 1);
- m.visitEnd();
- (mv = cw.visitMethod(ACC_PUBLIC, "setValue",
- "(Ljava/lang/Object;Ljava/lang/Object;L" + NAMESPACE
- + "integration/VariableResolverFactory;Ljava/lang/Object;)Ljava/lang/Object;", null, null)).visitCode();
- }
- public Accessor optimizeAccessor(ParserContext pCtx, char[] property, int start, int offset, Object staticContext,
- Object thisRef, VariableResolverFactory factory, boolean root, Class ingressType) {
- time = System.currentTimeMillis();
- if (compiledInputs == null) compiledInputs = new ArrayList<ExecutableStatement>();
- this.start = cursor = start;
- this.end = start + offset;
- this.length = end - this.start;
- this.first = true;
- this.val = null;
- this.pCtx = pCtx;
- this.expr = property;
- this.ctx = staticContext;
- this.thisRef = thisRef;
- this.variableFactory = factory;
- this.ingressType = ingressType;
- if (!noinit) _initJIT();
- return compileAccessor();
- }
- public Accessor optimizeSetAccessor(ParserContext pCtx, char[] property, int start, int offset, Object ctx,
- Object thisRef, VariableResolverFactory factory, boolean rootThisRef,
- Object value, Class ingressType) {
- this.expr = property;
- this.start = this.cursor = start;
- this.end = start + offset;
- this.length = start + offset;
- this.first = true;
- this.ingressType = ingressType;
- compiledInputs = new ArrayList<ExecutableStatement>();
- this.pCtx = pCtx;
- this.ctx = ctx;
- this.thisRef = thisRef;
- this.variableFactory = factory;
- char[] root = null;
- PropertyVerifier verifier = new PropertyVerifier(property, this.pCtx = pCtx);
- int split = findLastUnion();
- if (split != -1) {
- root = subset(property, 0, split);
- }
- AccessorNode rootAccessor = null;
- _initJIT2();
- if (root != null) {
- int _length = this.length;
- int _end = this.end;
- char[] _expr = this.expr;
- this.length = end = (this.expr = root).length;
- // run the compiler but don't finish building.
- deferFinish = true;
- noinit = true;
- compileAccessor();
- ctx = this.val;
- this.expr = _expr;
- this.cursor = start + root.length + 1;
- this.length = _length - root.length - 1;
- this.end = this.cursor + this.length;
- }
- else {
- assert debug("ALOAD 1");
- mv.visitVarInsn(ALOAD, 1);
- }
- try {
- skipWhitespace();
- if (collection) {
- int st = cursor;
- whiteSpaceSkip();
- if (st == end)
- throw new PropertyAccessException("unterminated '['", expr, start);
- if (scanTo(']'))
- throw new PropertyAccessException("unterminated '['", expr, start);
- String ex = new String(expr, st, cursor - st).trim();
- assert debug("CHECKCAST " + ctx.getClass().getName());
- mv.visitTypeInsn(CHECKCAST, getInternalName(ctx.getClass()));
- if (ctx instanceof Map) {
- if (MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING && hasPropertyHandler(Map.class)) {
- propHandlerByteCodePut(ex, ctx, Map.class, value);
- }
- else {
- //noinspection unchecked
- ((Map) ctx).put(eval(ex, ctx, variableFactory), convert(value, returnType = verifier.analyze()));
- writeLiteralOrSubexpression(subCompileExpression(ex.toCharArray(), pCtx));
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- if (value != null & returnType != value.getClass()) {
- dataConversion(returnType);
- checkcast(returnType);
- }
- assert debug("INVOKEINTERFACE Map.put");
- mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "put",
- "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
- assert debug("POP");
- mv.visitInsn(POP);
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- }
- }
- else if (ctx instanceof List) {
- if (MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING && hasPropertyHandler(List.class)) {
- propHandlerByteCodePut(ex, ctx, List.class, value);
- }
- else {
- //noinspection unchecked
- ((List) ctx).set(eval(ex, ctx, variableFactory, Integer.class),
- convert(value, returnType = verifier.analyze()));
- writeLiteralOrSubexpression(subCompileExpression(ex.toCharArray(), pCtx));
- unwrapPrimitive(int.class);
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- if (value != null & !value.getClass().isAssignableFrom(returnType)) {
- dataConversion(returnType);
- checkcast(returnType);
- }
- assert debug("INVOKEINTERFACE List.set");
- mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "set", "(ILjava/lang/Object;)Ljava/lang/Object;");
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- }
- }
- else if (MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING && hasPropertyHandler(ctx.getClass())) {
- propHandlerByteCodePut(ex, ctx, ctx.getClass(), value);
- }
- else if (ctx.getClass().isArray()) {
- if (MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING && hasPropertyHandler(Array.class)) {
- propHandlerByteCodePut(ex, ctx, Array.class, value);
- }
- else {
- Class type = getBaseComponentType(ctx.getClass());
- Object idx = eval(ex, ctx, variableFactory);
- writeLiteralOrSubexpression(subCompileExpression(ex.toCharArray(), pCtx), int.class);
- if (!(idx instanceof Integer)) {
- dataConversion(Integer.class);
- idx = DataConversion.convert(idx, Integer.class);
- unwrapPrimitive(int.class);
- }
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- if (type.isPrimitive()) unwrapPrimitive(type);
- else if (!type.equals(value.getClass())) {
- dataConversion(type);
- }
- arrayStore(type);
- //noinspection unchecked
- Array.set(ctx, (Integer) idx, convert(value, type));
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- }
- }
- else {
- throw new PropertyAccessException("cannot bind to collection property: " + new String(expr)
- + ": not a recognized collection type: " + ctx.getClass(), expr, start);
- }
- deferFinish = false;
- noinit = false;
- _finishJIT();
- try {
- deferFinish = false;
- return _initializeAccessor();
- }
- catch (Exception e) {
- throw new CompileException("could not generate accessor", expr, start, e);
- }
- }
- String tk = new String(expr, this.cursor, this.length);
- Member member = getFieldOrWriteAccessor(ctx.getClass(), tk, value == null ? null : ingressType);
- if (GlobalListenerFactory.hasSetListeners()) {
- mv.visitVarInsn(ALOAD, 1);
- mv.visitLdcInsn(tk);
- mv.visitVarInsn(ALOAD, 3);
- mv.visitVarInsn(ALOAD, 4);
- mv.visitMethodInsn(INVOKESTATIC, NAMESPACE + "integration/GlobalListenerFactory",
- "notifySetListeners", "(Ljava/lang/Object;Ljava/lang/String;L" + NAMESPACE
- + "integration/VariableResolverFactory;Ljava/lang/Object;)V");
- GlobalListenerFactory.notifySetListeners(ctx, tk, variableFactory, value);
- }
- if (member instanceof Field) {
- checkcast(ctx.getClass());
- Field fld = (Field) member;
- Label jmp = null;
- Label jmp2 = new Label();
- if (fld.getType().isPrimitive()) {
- assert debug("ASTORE 5");
- mv.visitVarInsn(ASTORE, 5);
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- if (value == null) value = PropertyTools.getPrimitiveInitialValue(fld.getType());
- jmp = new Label();
- assert debug("IFNOTNULL jmp");
- mv.visitJumpInsn(IFNONNULL, jmp);
- assert debug("ALOAD 5");
- mv.visitVarInsn(ALOAD, 5);
- assert debug("ICONST_0");
- mv.visitInsn(ICONST_0);
- assert debug("PUTFIELD " + getInternalName(fld.getDeclaringClass()) + "." + tk);
- mv.visitFieldInsn(PUTFIELD, getInternalName(fld.getDeclaringClass()), tk, getDescriptor(fld.getType()));
- assert debug("GOTO jmp2");
- mv.visitJumpInsn(GOTO, jmp2);
- assert debug("jmp:");
- mv.visitLabel(jmp);
- assert debug("ALOAD 5");
- mv.visitVarInsn(ALOAD, 5);
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- unwrapPrimitive(fld.getType());
- }
- else {
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- checkcast(fld.getType());
- }
- if (jmp == null && value != null && !fld.getType().isAssignableFrom(value.getClass())) {
- if (!canConvert(fld.getType(), value.getClass())) {
- throw new CompileException("cannot convert type: "
- + value.getClass() + ": to " + fld.getType(), expr, start);
- }
- dataConversion(fld.getType());
- fld.set(ctx, convert(value, fld.getType()));
- }
- else {
- fld.set(ctx, value);
- }
- assert debug("PUTFIELD " + getInternalName(fld.getDeclaringClass()) + "." + tk);
- mv.visitFieldInsn(PUTFIELD, getInternalName(fld.getDeclaringClass()), tk, getDescriptor(fld.getType()));
- assert debug("jmp2:");
- mv.visitLabel(jmp2);
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- }
- else if (member != null) {
- assert debug("CHECKCAST " + getInternalName(ctx.getClass()));
- mv.visitTypeInsn(CHECKCAST, getInternalName(ctx.getClass()));
- Method meth = (Method) member;
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- Class targetType = meth.getParameterTypes()[0];
- Label jmp = null;
- Label jmp2 = new Label();
- if (value != null && !targetType.isAssignableFrom(value.getClass())) {
- if (!canConvert(targetType, value.getClass())) {
- throw new CompileException("cannot convert type: "
- + value.getClass() + ": to " + meth.getParameterTypes()[0], expr, start);
- }
- dataConversion(getWrapperClass(targetType));
- if (targetType.isPrimitive()) {
- unwrapPrimitive(targetType);
- }
- else checkcast(targetType);
- meth.invoke(ctx, convert(value, meth.getParameterTypes()[0]));
- }
- else {
- if (targetType.isPrimitive()) {
- if (value == null) value = PropertyTools.getPrimitiveInitialValue(targetType);
- jmp = new Label();
- assert debug("IFNOTNULL jmp");
- mv.visitJumpInsn(IFNONNULL, jmp);
- assert debug("ICONST_0");
- mv.visitInsn(ICONST_0);
- assert debug("INVOKEVIRTUAL " + getInternalName(meth.getDeclaringClass()) + "." + meth.getName());
- mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(meth.getDeclaringClass()), meth.getName(),
- getMethodDescriptor(meth));
- assert debug("GOTO jmp2");
- mv.visitJumpInsn(GOTO, jmp2);
- assert debug("jmp:");
- mv.visitLabel(jmp);
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- unwrapPrimitive(targetType);
- }
- else {
- checkcast(targetType);
- }
- meth.invoke(ctx, value);
- }
- assert debug("INVOKEVIRTUAL " + getInternalName(meth.getDeclaringClass()) + "." + meth.getName());
- mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(meth.getDeclaringClass()), meth.getName(),
- getMethodDescriptor(meth));
- assert debug("jmp2:");
- mv.visitLabel(jmp2);
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- }
- else if (ctx instanceof Map) {
- assert debug("CHECKCAST " + getInternalName(ctx.getClass()));
- mv.visitTypeInsn(CHECKCAST, getInternalName(ctx.getClass()));
- assert debug("LDC '" + tk + "'");
- mv.visitLdcInsn(tk);
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- assert debug("INVOKEVIRTUAL java/util/HashMap.put");
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
- assert debug("ALOAD 4");
- mv.visitVarInsn(ALOAD, 4);
- //noinspection unchecked
- ((Map) ctx).put(tk, value);
- }
- else {
- throw new PropertyAccessException("could not access property (" + tk + ") in: "
- + ingressType.getName(), expr, start);
- }
- }
- catch (InvocationTargetException e) {
- throw new PropertyAccessException("could not access property", expr, start, e);
- }
- catch (IllegalAccessException e) {
- throw new PropertyAccessException("could not access property", expr, start, e);
- }
- try {
- deferFinish = false;
- noinit = false;
- _finishJIT();
- return _initializeAccessor();
- }
- catch (Exception e) {
- throw new CompileException("could not generate accessor", expr, start, e);
- }
- }
- private void _finishJIT() {
- if (deferFinish) {
- return;
- }
- if (returnType != null && returnType.isPrimitive()) {
- //noinspection unchecked
- wrapPrimitive(returnType);
- }
- if (returnType == void.class) {
- assert debug("ACONST_NULL");
- mv.visitInsn(ACONST_NULL);
- }
- assert debug("ARETURN");
- mv.visitInsn(ARETURN);
- assert debug("\n{METHOD STATS (maxstack=" + stacksize + ")}\n");
- dumpAdvancedDebugging(); // dump advanced debugging if necessary
- mv.visitMaxs(stacksize, maxlocals);
- mv.visitEnd();
- mv = cw.visitMethod(ACC_PUBLIC, "getKnownEgressType", "()Ljava/lang/Class;", null, null);
- mv.visitCode();
- visitConstantClass(returnType);
- mv.visitInsn(ARETURN);
- mv.visitMaxs(1, 1);
- mv.visitEnd();
- if (propNull) {
- cw.visitField(ACC_PUBLIC, "nullPropertyHandler", "L" + NAMESPACE + "integration/PropertyHandler;", null, null).visitEnd();
- }
- if (methNull) {
- cw.visitField(ACC_PUBLIC, "nullMethodHandler", "L" + NAMESPACE + "integration/PropertyHandler;", null, null).visitEnd();
- }
- buildInputs();
- if (buildLog != null && buildLog.length() != 0 && expr != null) {
- mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
- mv.visitCode();
- Label l0 = new Label();
- mv.visitLabel(l0);
- mv.visitLdcInsn(buildLog.toString() + "\n\n## { " + new String(expr) + " }");
- mv.visitInsn(ARETURN);
- Label l1 = new Label();
- mv.visitLabel(l1);
- mv.visitMaxs(1, 1);
- mv.visitEnd();
- }
- cw.visitEnd();
- }
- private void visitConstantClass(Class<?> clazz) {
- if (clazz == null) clazz = Object.class;
- if (clazz.isPrimitive()) {
- mv.visitFieldInsn(GETSTATIC, toNonPrimitiveType(clazz).getName().replace(".", "/"), "TYPE", "Ljava/lang/Class;");
- } else {
- mv.visitLdcInsn(org.mvel2.asm.Type.getType(clazz));
- }
- }
- private Accessor _initializeAccessor() throws Exception {
- if (deferFinish) {
- return null;
- }
- /**
- * Hot load the class we just generated.
- */
- Class cls = loadClass(className, cw.toByteArray());
- assert debug("[MVEL JIT Completed Optimization <<" + (expr != null ? new String(expr) : "") + ">>]::" + cls
- + " (time: " + (System.currentTimeMillis() - time) + "ms)");
- Object o;
- try {
- if (compiledInputs.size() == 0) {
- o = cls.newInstance();
- }
- else {
- Class[] parms = new Class[compiledInputs.size()];
- for (int i = 0; i < compiledInputs.size(); i++) {
- parms[i] = ExecutableStatement.class;
- }
- o = cls.getConstructor(parms).newInstance(compiledInputs.toArray(new ExecutableStatement[compiledInputs.size()]));
- }
- if (propNull) cls.getField("nullPropertyHandler").set(o, getNullPropertyHandler());
- if (methNull) cls.getField("nullMethodHandler").set(o, getNullMethodHandler());
- }
- catch (VerifyError e) {
- System.out.println("**** COMPILER BUG! REPORT THIS IMMEDIATELY AT http://jira.codehaus.org/browse/mvel2");
- System.out.println("Expression: " + (expr == null ? null : new String(expr)));
- throw e;
- }
- return (Accessor) o;
- }
- private Accessor compileAccessor() {
- assert debug("<<INITIATE COMPILE>>");
- Object curr = ctx;
- try {
- if (!MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING) {
- while (cursor < end) {
- switch (nextSubToken()) {
- case BEAN:
- curr = getBeanProperty(curr, capture());
- break;
- case METH:
- curr = getMethod(curr, capture());
- break;
- case COL:
- curr = getCollectionProperty(curr, capture());
- break;
- case WITH:
- curr = getWithProperty(curr);
- break;
- }
- // check to see if a null safety is enabled on this property.
- if (fields == -1) {
- if (curr == null) {
- if (nullSafe) {
- throw new OptimizationNotSupported();
- }
- break;
- }
- else {
- fields = 0;
- }
- }
- first = false;
- if (nullSafe && cursor < end) {
- assert debug("DUP");
- mv.visitInsn(DUP);
- Label j = new Label();
- assert debug("IFNONNULL : jump");
- mv.visitJumpInsn(IFNONNULL, j);
- assert debug("ARETURN");
- mv.visitInsn(ARETURN);
- assert debug("LABEL:jump");
- mv.visitLabel(j);
- }
- }
- }
- else {
- while (cursor < end) {
- switch (nextSubToken()) {
- case BEAN:
- curr = getBeanPropertyAO(curr, capture());
- break;
- case METH:
- curr = getMethod(curr, capture());
- break;
- case COL:
- curr = getCollectionPropertyAO(curr, capture());
- break;
- case WITH:
- curr = getWithProperty(curr);
- break;
- }
- // check to see if a null safety is enabled on this property.
- if (fields == -1) {
- if (curr == null) {
- if (nullSafe) {
- throw new OptimizationNotSupported();
- }
- break;
- }
- else {
- fields = 0;
- }
- }
- first = false;
- if (nullSafe && cursor < end) {
- assert debug("DUP");
- mv.visitInsn(DUP);
- Label j = new Label();
- assert debug("IFNONNULL : jump");
- mv.visitJumpInsn(IFNONNULL, j);
- assert debug("ARETURN");
- mv.visitInsn(ARETURN);
- assert debug("LABEL:jump");
- mv.visitLabel(j);
- }
- }
- }
- val = curr;
- _finishJIT();
- return _initializeAccessor();
- }
- catch (InvocationTargetException e) {
- throw new PropertyAccessException(new String(expr), expr, st, e);
- }
- catch (IllegalAccessException e) {
- throw new PropertyAccessException(new String(expr), expr, st, e);
- }
- catch (IndexOutOfBoundsException e) {
- throw new PropertyAccessException(new String(expr), expr, st, e);
- }
- catch (PropertyAccessException e) {
- throw new CompileException(e.getMessage(), expr, st, e);
- }
- catch (CompileException e) {
- throw e;
- }
- catch (NullPointerException e) {
- throw new PropertyAccessException(new String(expr), expr, st, e);
- }
- catch (OptimizationNotSupported e) {
- throw e;
- }
- catch (Exception e) {
- throw new CompileException(e.getMessage(), expr, st, e);
- }
- }
- private Object getWithProperty(Object ctx) {
- assert debug("\n ** ENTER -> {with}");
- if (first) {
- assert debug("ALOAD 1");
- mv.visitVarInsn(ALOAD, 1);
- first = false;
- }
- String root = new String(expr, 0, cursor - 1).trim();
- int start = cursor + 1;
- cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '{', pCtx);
- this.returnType = ctx != null ? ctx.getClass() : null;
- for (WithNode.ParmValuePair aPvp : WithNode.compileWithExpressions(expr, start, cursor++ - start, root, ingressType, pCtx)) {
- assert debug("DUP");
- mv.visitInsn(DUP);
- assert debug("ASTORE " + (5 + compileDepth) + " (withctx)");
- mv.visitVarInsn(ASTORE, 5 + compileDepth);
- aPvp.eval(ctx, variableFactory);
- if (aPvp.getSetExpression() == null) {
- addSubstatement(aPvp.getStatement());
- }
- else {
- compiledInputs.add((ExecutableStatement) aPvp.getSetExpression());
- // load set expression
- assert debug("ALOAD 0");
- mv.visitVarInsn(ALOAD, 0);
- assert debug("GETFIELD p" + (compiledInputs.size() - 1));
- mv.visitFieldInsn(GETFIELD, className, "p" + (compiledInputs.size() - 1), "L" + NAMESPACE
- + "compiler/ExecutableStatement;");
- // ctx
- assert debug("ALOAD " + (5 + compileDepth) + "(withctx)");
- mv.visitVarInsn(ALOAD, (5 + compileDepth));
- // elCtx
- assert debug("ALOAD 2");
- mv.visitVarInsn(ALOAD, 2);
- // variable factory
- assert debug("ALOAD 3");
- mv.visitVarInsn(ALOAD, 3);
- // the value to set.
- addSubstatement(aPvp.getStatement());
- assert debug("INVOKEINTERFACE Accessor.setValue");
- mv.visitMethodInsn(INVOKEINTERFACE, NAMESPACE + "compiler/ExecutableStatement",
- "setValue",
- "(Ljava/lang/Object;Ljava/lang/Object;L"
- + NAMESPACE + "integration/VariableResolverFactory;Ljava/lang/Object;)Ljava/lang/Object;");
- assert debug("POP");
- mv.visitInsn(POP);
- }
- }
- return ctx;
- }
- private Object getBeanPropertyAO(Object ctx, String property)
- throws IllegalAccessException, InvocationTargetException {
- if (ctx != null && hasPropertyHandler(ctx.getClass())) {
- return propHandlerByteCode(property, ctx, ctx.getClass());
- }
- return getBeanProperty(ctx, property);
- }
- 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) {
- Object o = ((Field) member).get(ctx);
- if (((member.getModifiers() & STATIC) != 0)) {
- // Check if the static field reference is a constant and a primitive.
- if ((member.getModifiers() & FINAL) != 0 && (o instanceof String || ((Field) member).getType().isPrimitive())) {
- o = ((Field) member).get(null);
- assert debug("LDC " + valueOf(o));
- mv.visitLdcInsn(o);
- wrapPrimitive(o.getClass());
- if (hasNullPropertyHandler()) {
- if (o == null) {
- o = getNullPropertyHandler().getProperty(member.getName(), ctx, variableFactory);
- }
- writeOutNullHandler(member, 0);
- }
- return o;
- }
- else {
- assert debug("GETSTATIC " + getDescriptor(member.getDeclaringClass()) + "."
- + member.getName() + "::" + getDescriptor(((Field) member).getType()));
- mv.visitFieldInsn(GETSTATIC, getInternalName(member.getDeclaringClass()),
- member.getName(), getDescriptor(returnType = ((Field) member).getType()));
- }
- }
- else {
- assert debug("CHECKCAST " + getInternalName(cls));
- mv.visitTypeInsn(CHECKCAST, getInternalName(cls));
- assert debug("GETFIELD " + property + ":" + getDescriptor(((Field) member).getType()));
- mv.visitFieldInsn(GETFIELD, getInternalName(cls), property, getDescriptor(returnType = ((Field) member)
- .getType()));
- }
- returnType = ((Field) member).getType();
- if (hasNullPropertyHandler()) {
- if (o == null) {
- o = getNullPropertyHandler().getProperty(member.getName(), ctx, variableFactory);
- }
- writeOutNullHandler(member, 0);
- }
- currType = toNonPrimitiveType(returnType);
- return o;
- }
- 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();
- 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);
- 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");
- mv.visitVarInsn(ALOAD, 2); // load the thisRef value.
- 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;
- if ((f.getModifiers() & FINAL) != 0) {
- Object finalVal = f.get(null);
- assert debug("LDC " + valueOf(finalVal));
- mv.visitLdcInsn(finalVal);
- wrapPrimitive(finalVal.getClass());
- return finalVal;
- }
- else {
- assert debug("GETSTATIC " + getInternalName(f.getDeclaringClass()) + "."
- + ((Field) ts).getName() + "::" + getDescriptor(f.getType()));
- mv.visitFieldInsn(GETSTATIC, getInternalName(f.getDeclaringClass()),
- f.getName(), getDescriptor(returnType = f.getType()));
- return f.get(null);
- }
- }
- }
- 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 (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 (MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL) {
- return getMethod(ctx, property);
- }
- if (ctx == null) {
- throw new PropertyAccessException("unresolvable property or identifier: " + property, expr, st);
- }
- else {
- throw new PropertyAccessException("could not access: " + property + "; in class: "
- + ctx.getClass().getName(), expr, st);
- }
- }
- }
- 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;
- }
- private Object getCollectionProperty(Object ctx, String prop)
- throws IllegalAccessException, InvocationTargetException {
- if (prop.trim().length() > 0) {
- ctx = getBeanProperty(ctx, prop);
- first = false;
- }
- currType = null;
- if (ctx == null) return null;
- assert debug("\n ** ENTER -> {collection:<<" + prop + ">>; ctx=" + ctx + "}");
- if (first) {
- assert debug("ALOAD 1");
- mv.visitVarInsn(ALOAD, 1);
- }
- int start = ++cursor;
- skipWhitespace();
- if (cursor == end)
- throw new CompileException("unterminated '['", expr, st);
- if (scanTo(']'))
- throw new CompileException("unterminated '['", expr, st);
- String tk = new String(expr, start, cursor - start);
- assert debug("{collection token: [" + tk + "]}");
- ExecutableStatement compiled = (ExecutableStatement) subCompileExpression(tk.toCharArray(), pCtx);
- Object item = compiled.getValue(ctx, variableFactory);
- ++cursor;
- if (ctx instanceof Map) {
- assert debug("CHECKCAST java/util/Map");
- mv.visitTypeInsn(CHECKCAST, "java/util/Map");
- Class c = writeLiteralOrSubexpression(compiled);
- if (c != null && c.isPrimitive()) {
- wrapPrimitive(c);
- }
- assert debug("INVOKEINTERFACE: get");
- mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
- return ((Map) ctx).get(item);
- }
- else if (ctx instanceof List) {
- assert debug("CHECKCAST java/util/List");
- mv.visitTypeInsn(CHECKCAST, "java/util/List");
- writeLiteralOrSubexpression(compiled, int.class);
- assert debug("INVOKEINTERFACE: java/util/List.get");
- mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;");
- return ((List) ctx).get(convert(item, Integer.class));
- }
- else if (ctx.getClass().isArray()) {
- assert debug("CHECKCAST " + getDescriptor(ctx.getClass()));
- mv.visitTypeInsn(CHECKCAST, getDescriptor(ctx.getClass()));
- writeLiteralOrSubexpression(compiled, int.class, item.getClass());
- Class cls = getBaseComponentType(ctx.getClass());
- if (cls.isPrimitive()) {
- if (cls == int.class) {
- assert debug("IALOAD");
- mv.visitInsn(IALOAD);
- }
- else if (cls == char.class) {
- assert debug("CALOAD");
- mv.visitInsn(CALOAD);
- }
- else if (cls == boolean.class) {
- assert debug("BALOAD");
- mv.visitInsn(BALOAD);
- }
- else if (cls == double.class) {
- assert debug("DALOAD");
- mv.visitInsn(DALOAD);
- }
- else if (cls == float.class) {
- assert debug("FALOAD");
- mv.visitInsn(FALOAD);
- }
- else if (cls == short.class) {
- assert debug("SALOAD");
- mv.visitInsn(SALOAD);
- }
- else if (cls == long.class) {
- assert debug("LALOAD");
- mv.visitInsn(LALOAD);
- }
- else if (cls == byte.class) {
- assert debug("BALOAD");
- mv.visitInsn(BALOAD);
- }
- wrapPrimitive(cls);
- }
- else {
- assert debug("AALOAD");
- mv.visitInsn(AALOAD);
- }
- return Array.get(ctx, convert(item, Integer.class));
- }
- else if (ctx instanceof CharSequence) {
- assert debug("CHECKCAST java/lang/CharSequence");
- mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence");
- if (item instanceof Integer) {
- intPush((Integer) item);
- assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
- mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "charAt", "(I)C");
- wrapPrimitive(char.class);
- return ((CharSequence) ctx).charAt((Integer) item);
- }
- else {
- writeLiteralOrSubexpression(compiled, Integer.class);
- unwrapPrimitive(int.class);
- assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
- mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "charAt", "(I)C");
- wrapPrimitive(char.class);
- return ((CharSequence) ctx).charAt(convert(item, Integer.class));
- }
- }
- else {
- TypeDescriptor tDescr = new TypeDescriptor(expr, this.start, length, 0);
- if (tDescr.isArray()) {
- try {
- Class cls = getClassReference((Class) ctx, tDescr, variableFactory, pCtx);
- // rootNode = new StaticReferenceAccessor(cls);
- ldcClassConstant(cls);
- return cls;
- }
- catch (Exception e) {
- //fall through
- }
- }
- throw new CompileException("illegal use of []: unknown type: "
- + (ctx == null ? null : ctx.getClass().getName()), expr, st);
- }
- }
- private Object getCollectionPropertyAO(Object ctx, String prop)
- throws IllegalAccessException, InvocationTargetException {
- if (prop.length() > 0) {
- ctx = getBeanProperty(ctx, prop);
- first = false;
- }
- currType = null;
- if (ctx == null) return null;
- assert debug("\n ** ENTER -> {collection:<<" + prop + ">>; ctx=" + ctx + "}");
- int _start = ++cursor;
- skipWhitespace();
- if (cursor == end)
- throw new CompileException("unterminated '['", expr, st);
- if (scanTo(']'))
- throw new CompileException("unterminated '['", expr, st);
- String tk = new String(expr, _start, cursor - _start);
- assert debug("{collection token:<<" + tk + ">>}");
- ExecutableStatement compiled = (ExecutableStatement) subCompileExpression(tk.toCharArray());
- Object item = compiled.getValue(ctx, variableFactory);
- ++cursor;
- if (ctx instanceof Map) {
- if (hasPropertyHandler(Map.class)) {
- return propHandlerByteCode(tk, ctx, Map.class);
- }
- else {
- if (first) {
- assert debug("ALOAD 1");
- mv.visitVarInsn(ALOAD, 1);
- }
- assert debug("CHECKCAST java/util/Map");
- mv.visitTypeInsn(CHECKCAST, "java/util/Map");
- Class c = writeLiteralOrSubexpression(compiled);
- if (c != null && c.isPrimitive()) {
- wrapPrimitive(c);
- }
- assert debug("INVOKEINTERFACE: Map.get");
- mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
- }
- return ((Map) ctx).get(item);
- }
- else if (ctx instanceof List) {
- if (hasPropertyHandler(List.class)) {
- return propHandlerByteCode(tk, ctx, List.class);
- }
- else {
- if (first) {
- assert debug("ALOAD 1");
- mv.visitVarInsn(ALOAD, 1);
- }
- assert debug("CHECKCAST java/util/List");
- mv.visitTypeInsn(CHECKCAST, "java/util/List");
- writeLiteralOrSubexpression(compiled, int.class);
- assert debug("INVOKEINTERFACE: java/util/List.get");
- mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;");
- return ((List) ctx).get(convert(item, Integer.class));
- }
- }
- else if (ctx.getClass().isArray()) {
- if (hasPropertyHandler(Array.class)) {
- return propHandlerByteCode(tk, ctx, Array.class);
- }
- else {
- if (first) {
- assert debug("ALOAD 1");
- mv.visitVarInsn(ALOAD, 1);
- }
- assert debug("CHECKCAST " + getDescriptor(ctx.getClass()));
- mv.visitTypeInsn(CHECKCAST, getDescriptor(ctx.getClass()));
- writeLiteralOrSubexpression(compiled, int.class, item.getClass());
- …
Large files files are truncated, but you can click here to view the full file