PageRenderTime 62ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/src/main/java/org/mvel2/optimizers/impl/asm/ASMAccessorOptimizer.java

https://github.com/sherl0cks/mvel
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

  1. /**
  2. * MVEL 2.0
  3. * Copyright (C) 2007 The Codehaus
  4. * Mike Brock, Dhanji Prasanna, John Graham, Mark Proctor
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.mvel2.optimizers.impl.asm;
  19. import org.mvel2.*;
  20. import org.mvel2.asm.ClassWriter;
  21. import org.mvel2.asm.Label;
  22. import org.mvel2.asm.MethodVisitor;
  23. import org.mvel2.asm.Opcodes;
  24. import org.mvel2.ast.*;
  25. import org.mvel2.compiler.*;
  26. import org.mvel2.integration.GlobalListenerFactory;
  27. import org.mvel2.integration.PropertyHandler;
  28. import org.mvel2.integration.VariableResolverFactory;
  29. import org.mvel2.optimizers.AbstractOptimizer;
  30. import org.mvel2.optimizers.AccessorOptimizer;
  31. import org.mvel2.optimizers.OptimizationNotSupported;
  32. import org.mvel2.optimizers.impl.refl.nodes.Union;
  33. import org.mvel2.util.*;
  34. import java.io.FileWriter;
  35. import java.io.IOException;
  36. import java.lang.reflect.*;
  37. import java.util.ArrayList;
  38. import java.util.Arrays;
  39. import java.util.List;
  40. import java.util.Map;
  41. import static java.lang.String.valueOf;
  42. import static java.lang.System.getProperty;
  43. import static java.lang.Thread.currentThread;
  44. import static java.lang.reflect.Array.getLength;
  45. import static java.lang.reflect.Modifier.FINAL;
  46. import static java.lang.reflect.Modifier.STATIC;
  47. import static org.mvel2.DataConversion.canConvert;
  48. import static org.mvel2.DataConversion.convert;
  49. import static org.mvel2.MVEL.eval;
  50. import static org.mvel2.MVEL.isAdvancedDebugging;
  51. import static org.mvel2.asm.Opcodes.*;
  52. import static org.mvel2.asm.Type.*;
  53. import static org.mvel2.ast.TypeDescriptor.getClassReference;
  54. import static org.mvel2.integration.GlobalListenerFactory.hasGetListeners;
  55. import static org.mvel2.integration.GlobalListenerFactory.notifyGetListeners;
  56. import static org.mvel2.integration.PropertyHandlerFactory.*;
  57. import static org.mvel2.util.ArrayTools.findFirst;
  58. import static org.mvel2.util.ParseTools.*;
  59. import static org.mvel2.util.PropertyTools.getFieldOrAccessor;
  60. import static org.mvel2.util.PropertyTools.getFieldOrWriteAccessor;
  61. import static org.mvel2.util.ReflectionUtil.toNonPrimitiveArray;
  62. import static org.mvel2.util.ReflectionUtil.toNonPrimitiveType;
  63. import static org.mvel2.util.Varargs.*;
  64. /**
  65. * Implementation of the MVEL Just-in-Time (JIT) compiler for Property Accessors using the ASM bytecode
  66. * engineering library.
  67. * <p/>
  68. */
  69. @SuppressWarnings({"TypeParameterExplicitlyExtendsObject", "unchecked", "UnusedDeclaration"})
  70. public class ASMAccessorOptimizer extends AbstractOptimizer implements AccessorOptimizer {
  71. private static final String MAP_IMPL = "java/util/HashMap";
  72. private static String LIST_IMPL;
  73. private static String NAMESPACE;
  74. private static final int OPCODES_VERSION;
  75. static {
  76. final String javaVersion = getProperty("java.version");
  77. if (javaVersion.startsWith("1.4"))
  78. OPCODES_VERSION = Opcodes.V1_4;
  79. else if (javaVersion.startsWith("1.5"))
  80. OPCODES_VERSION = Opcodes.V1_5;
  81. else if (javaVersion.startsWith("1.6") || javaVersion.startsWith("1.7"))
  82. OPCODES_VERSION = Opcodes.V1_6;
  83. else
  84. OPCODES_VERSION = Opcodes.V1_2;
  85. String defaultNameSapce = getProperty("mvel2.namespace");
  86. if (defaultNameSapce == null) NAMESPACE = "org/mvel2/";
  87. else NAMESPACE = defaultNameSapce;
  88. String jitListImpl = getProperty("mvel2.jit.list_impl");
  89. if (jitListImpl == null) LIST_IMPL = NAMESPACE + "util/FastList";
  90. else LIST_IMPL = jitListImpl;
  91. }
  92. private Object ctx;
  93. private Object thisRef;
  94. private VariableResolverFactory variableFactory;
  95. private static final Object[] EMPTYARG = new Object[0];
  96. private static final Class[] EMPTYCLS = new Class[0];
  97. private boolean first = true;
  98. private boolean noinit = false;
  99. private boolean deferFinish = false;
  100. private boolean literal = false;
  101. private boolean propNull = false;
  102. private boolean methNull = false;
  103. private String className;
  104. private ClassWriter cw;
  105. private MethodVisitor mv;
  106. private Object val;
  107. private int stacksize = 1;
  108. private int maxlocals = 1;
  109. private long time;
  110. private ArrayList<ExecutableStatement> compiledInputs;
  111. private Class ingressType;
  112. private Class returnType;
  113. private int compileDepth = 0;
  114. @SuppressWarnings({"StringBufferField"})
  115. private StringAppender buildLog;
  116. public ASMAccessorOptimizer() {
  117. //do this to confirm we're running the correct version
  118. //otherwise should create a verification error in VM
  119. new ClassWriter(ClassWriter.COMPUTE_MAXS);
  120. }
  121. private ASMAccessorOptimizer(ClassWriter cw, MethodVisitor mv,
  122. ArrayList<ExecutableStatement> compiledInputs, String className,
  123. StringAppender buildLog, int compileDepth) {
  124. this.cw = cw;
  125. this.mv = mv;
  126. this.compiledInputs = compiledInputs;
  127. this.className = className;
  128. this.buildLog = buildLog;
  129. this.compileDepth = compileDepth + 1;
  130. noinit = true;
  131. deferFinish = true;
  132. }
  133. /**
  134. * Does all the boilerplate for initiating the JIT.
  135. */
  136. private void _initJIT() {
  137. if (isAdvancedDebugging()) {
  138. buildLog = new StringAppender();
  139. }
  140. cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
  141. synchronized (Runtime.getRuntime()) {
  142. cw.visit(OPCODES_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, className = "ASMAccessorImpl_"
  143. + valueOf(cw.hashCode()).replaceAll("\\-", "_") + (System.currentTimeMillis() / 10) +
  144. ((int) Math.random() * 100),
  145. null, "java/lang/Object", new String[]{NAMESPACE + "compiler/Accessor"});
  146. }
  147. MethodVisitor m = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
  148. m.visitCode();
  149. m.visitVarInsn(Opcodes.ALOAD, 0);
  150. m.visitMethodInsn(INVOKESPECIAL, "java/lang/Object",
  151. "<init>", "()V");
  152. m.visitInsn(RETURN);
  153. m.visitMaxs(1, 1);
  154. m.visitEnd();
  155. (mv = cw.visitMethod(ACC_PUBLIC, "getValue",
  156. "(Ljava/lang/Object;Ljava/lang/Object;L" + NAMESPACE
  157. + "integration/VariableResolverFactory;)Ljava/lang/Object;", null, null)).visitCode();
  158. }
  159. private void _initJIT2() {
  160. if (isAdvancedDebugging()) {
  161. buildLog = new StringAppender();
  162. }
  163. cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
  164. synchronized (Runtime.getRuntime()) {
  165. cw.visit(OPCODES_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, className = "ASMAccessorImpl_"
  166. + valueOf(cw.hashCode()).replaceAll("\\-", "_") + (System.currentTimeMillis() / 10) +
  167. ((int) Math.random() * 100),
  168. null, "java/lang/Object", new String[]{NAMESPACE + "compiler/Accessor"});
  169. }
  170. MethodVisitor m = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
  171. m.visitCode();
  172. m.visitVarInsn(Opcodes.ALOAD, 0);
  173. m.visitMethodInsn(INVOKESPECIAL, "java/lang/Object",
  174. "<init>", "()V");
  175. m.visitInsn(RETURN);
  176. m.visitMaxs(1, 1);
  177. m.visitEnd();
  178. (mv = cw.visitMethod(ACC_PUBLIC, "setValue",
  179. "(Ljava/lang/Object;Ljava/lang/Object;L" + NAMESPACE
  180. + "integration/VariableResolverFactory;Ljava/lang/Object;)Ljava/lang/Object;", null, null)).visitCode();
  181. }
  182. public Accessor optimizeAccessor(ParserContext pCtx, char[] property, int start, int offset, Object staticContext,
  183. Object thisRef, VariableResolverFactory factory, boolean root, Class ingressType) {
  184. time = System.currentTimeMillis();
  185. if (compiledInputs == null) compiledInputs = new ArrayList<ExecutableStatement>();
  186. this.start = cursor = start;
  187. this.end = start + offset;
  188. this.length = end - this.start;
  189. this.first = true;
  190. this.val = null;
  191. this.pCtx = pCtx;
  192. this.expr = property;
  193. this.ctx = staticContext;
  194. this.thisRef = thisRef;
  195. this.variableFactory = factory;
  196. this.ingressType = ingressType;
  197. if (!noinit) _initJIT();
  198. return compileAccessor();
  199. }
  200. public Accessor optimizeSetAccessor(ParserContext pCtx, char[] property, int start, int offset, Object ctx,
  201. Object thisRef, VariableResolverFactory factory, boolean rootThisRef,
  202. Object value, Class ingressType) {
  203. this.expr = property;
  204. this.start = this.cursor = start;
  205. this.end = start + offset;
  206. this.length = start + offset;
  207. this.first = true;
  208. this.ingressType = ingressType;
  209. compiledInputs = new ArrayList<ExecutableStatement>();
  210. this.pCtx = pCtx;
  211. this.ctx = ctx;
  212. this.thisRef = thisRef;
  213. this.variableFactory = factory;
  214. char[] root = null;
  215. PropertyVerifier verifier = new PropertyVerifier(property, this.pCtx = pCtx);
  216. int split = findLastUnion();
  217. if (split != -1) {
  218. root = subset(property, 0, split);
  219. }
  220. AccessorNode rootAccessor = null;
  221. _initJIT2();
  222. if (root != null) {
  223. int _length = this.length;
  224. int _end = this.end;
  225. char[] _expr = this.expr;
  226. this.length = end = (this.expr = root).length;
  227. // run the compiler but don't finish building.
  228. deferFinish = true;
  229. noinit = true;
  230. compileAccessor();
  231. ctx = this.val;
  232. this.expr = _expr;
  233. this.cursor = start + root.length + 1;
  234. this.length = _length - root.length - 1;
  235. this.end = this.cursor + this.length;
  236. }
  237. else {
  238. assert debug("ALOAD 1");
  239. mv.visitVarInsn(ALOAD, 1);
  240. }
  241. try {
  242. skipWhitespace();
  243. if (collection) {
  244. int st = cursor;
  245. whiteSpaceSkip();
  246. if (st == end)
  247. throw new PropertyAccessException("unterminated '['", expr, start);
  248. if (scanTo(']'))
  249. throw new PropertyAccessException("unterminated '['", expr, start);
  250. String ex = new String(expr, st, cursor - st).trim();
  251. assert debug("CHECKCAST " + ctx.getClass().getName());
  252. mv.visitTypeInsn(CHECKCAST, getInternalName(ctx.getClass()));
  253. if (ctx instanceof Map) {
  254. if (MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING && hasPropertyHandler(Map.class)) {
  255. propHandlerByteCodePut(ex, ctx, Map.class, value);
  256. }
  257. else {
  258. //noinspection unchecked
  259. ((Map) ctx).put(eval(ex, ctx, variableFactory), convert(value, returnType = verifier.analyze()));
  260. writeLiteralOrSubexpression(subCompileExpression(ex.toCharArray(), pCtx));
  261. assert debug("ALOAD 4");
  262. mv.visitVarInsn(ALOAD, 4);
  263. if (value != null & returnType != value.getClass()) {
  264. dataConversion(returnType);
  265. checkcast(returnType);
  266. }
  267. assert debug("INVOKEINTERFACE Map.put");
  268. mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "put",
  269. "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
  270. assert debug("POP");
  271. mv.visitInsn(POP);
  272. assert debug("ALOAD 4");
  273. mv.visitVarInsn(ALOAD, 4);
  274. }
  275. }
  276. else if (ctx instanceof List) {
  277. if (MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING && hasPropertyHandler(List.class)) {
  278. propHandlerByteCodePut(ex, ctx, List.class, value);
  279. }
  280. else {
  281. //noinspection unchecked
  282. ((List) ctx).set(eval(ex, ctx, variableFactory, Integer.class),
  283. convert(value, returnType = verifier.analyze()));
  284. writeLiteralOrSubexpression(subCompileExpression(ex.toCharArray(), pCtx));
  285. unwrapPrimitive(int.class);
  286. assert debug("ALOAD 4");
  287. mv.visitVarInsn(ALOAD, 4);
  288. if (value != null & !value.getClass().isAssignableFrom(returnType)) {
  289. dataConversion(returnType);
  290. checkcast(returnType);
  291. }
  292. assert debug("INVOKEINTERFACE List.set");
  293. mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "set", "(ILjava/lang/Object;)Ljava/lang/Object;");
  294. assert debug("ALOAD 4");
  295. mv.visitVarInsn(ALOAD, 4);
  296. }
  297. }
  298. else if (MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING && hasPropertyHandler(ctx.getClass())) {
  299. propHandlerByteCodePut(ex, ctx, ctx.getClass(), value);
  300. }
  301. else if (ctx.getClass().isArray()) {
  302. if (MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING && hasPropertyHandler(Array.class)) {
  303. propHandlerByteCodePut(ex, ctx, Array.class, value);
  304. }
  305. else {
  306. Class type = getBaseComponentType(ctx.getClass());
  307. Object idx = eval(ex, ctx, variableFactory);
  308. writeLiteralOrSubexpression(subCompileExpression(ex.toCharArray(), pCtx), int.class);
  309. if (!(idx instanceof Integer)) {
  310. dataConversion(Integer.class);
  311. idx = DataConversion.convert(idx, Integer.class);
  312. unwrapPrimitive(int.class);
  313. }
  314. assert debug("ALOAD 4");
  315. mv.visitVarInsn(ALOAD, 4);
  316. if (type.isPrimitive()) unwrapPrimitive(type);
  317. else if (!type.equals(value.getClass())) {
  318. dataConversion(type);
  319. }
  320. arrayStore(type);
  321. //noinspection unchecked
  322. Array.set(ctx, (Integer) idx, convert(value, type));
  323. assert debug("ALOAD 4");
  324. mv.visitVarInsn(ALOAD, 4);
  325. }
  326. }
  327. else {
  328. throw new PropertyAccessException("cannot bind to collection property: " + new String(expr)
  329. + ": not a recognized collection type: " + ctx.getClass(), expr, start);
  330. }
  331. deferFinish = false;
  332. noinit = false;
  333. _finishJIT();
  334. try {
  335. deferFinish = false;
  336. return _initializeAccessor();
  337. }
  338. catch (Exception e) {
  339. throw new CompileException("could not generate accessor", expr, start, e);
  340. }
  341. }
  342. String tk = new String(expr, this.cursor, this.length);
  343. Member member = getFieldOrWriteAccessor(ctx.getClass(), tk, value == null ? null : ingressType);
  344. if (GlobalListenerFactory.hasSetListeners()) {
  345. mv.visitVarInsn(ALOAD, 1);
  346. mv.visitLdcInsn(tk);
  347. mv.visitVarInsn(ALOAD, 3);
  348. mv.visitVarInsn(ALOAD, 4);
  349. mv.visitMethodInsn(INVOKESTATIC, NAMESPACE + "integration/GlobalListenerFactory",
  350. "notifySetListeners", "(Ljava/lang/Object;Ljava/lang/String;L" + NAMESPACE
  351. + "integration/VariableResolverFactory;Ljava/lang/Object;)V");
  352. GlobalListenerFactory.notifySetListeners(ctx, tk, variableFactory, value);
  353. }
  354. if (member instanceof Field) {
  355. checkcast(ctx.getClass());
  356. Field fld = (Field) member;
  357. Label jmp = null;
  358. Label jmp2 = new Label();
  359. if (fld.getType().isPrimitive()) {
  360. assert debug("ASTORE 5");
  361. mv.visitVarInsn(ASTORE, 5);
  362. assert debug("ALOAD 4");
  363. mv.visitVarInsn(ALOAD, 4);
  364. if (value == null) value = PropertyTools.getPrimitiveInitialValue(fld.getType());
  365. jmp = new Label();
  366. assert debug("IFNOTNULL jmp");
  367. mv.visitJumpInsn(IFNONNULL, jmp);
  368. assert debug("ALOAD 5");
  369. mv.visitVarInsn(ALOAD, 5);
  370. assert debug("ICONST_0");
  371. mv.visitInsn(ICONST_0);
  372. assert debug("PUTFIELD " + getInternalName(fld.getDeclaringClass()) + "." + tk);
  373. mv.visitFieldInsn(PUTFIELD, getInternalName(fld.getDeclaringClass()), tk, getDescriptor(fld.getType()));
  374. assert debug("GOTO jmp2");
  375. mv.visitJumpInsn(GOTO, jmp2);
  376. assert debug("jmp:");
  377. mv.visitLabel(jmp);
  378. assert debug("ALOAD 5");
  379. mv.visitVarInsn(ALOAD, 5);
  380. assert debug("ALOAD 4");
  381. mv.visitVarInsn(ALOAD, 4);
  382. unwrapPrimitive(fld.getType());
  383. }
  384. else {
  385. assert debug("ALOAD 4");
  386. mv.visitVarInsn(ALOAD, 4);
  387. checkcast(fld.getType());
  388. }
  389. if (jmp == null && value != null && !fld.getType().isAssignableFrom(value.getClass())) {
  390. if (!canConvert(fld.getType(), value.getClass())) {
  391. throw new CompileException("cannot convert type: "
  392. + value.getClass() + ": to " + fld.getType(), expr, start);
  393. }
  394. dataConversion(fld.getType());
  395. fld.set(ctx, convert(value, fld.getType()));
  396. }
  397. else {
  398. fld.set(ctx, value);
  399. }
  400. assert debug("PUTFIELD " + getInternalName(fld.getDeclaringClass()) + "." + tk);
  401. mv.visitFieldInsn(PUTFIELD, getInternalName(fld.getDeclaringClass()), tk, getDescriptor(fld.getType()));
  402. assert debug("jmp2:");
  403. mv.visitLabel(jmp2);
  404. assert debug("ALOAD 4");
  405. mv.visitVarInsn(ALOAD, 4);
  406. }
  407. else if (member != null) {
  408. assert debug("CHECKCAST " + getInternalName(ctx.getClass()));
  409. mv.visitTypeInsn(CHECKCAST, getInternalName(ctx.getClass()));
  410. Method meth = (Method) member;
  411. assert debug("ALOAD 4");
  412. mv.visitVarInsn(ALOAD, 4);
  413. Class targetType = meth.getParameterTypes()[0];
  414. Label jmp = null;
  415. Label jmp2 = new Label();
  416. if (value != null && !targetType.isAssignableFrom(value.getClass())) {
  417. if (!canConvert(targetType, value.getClass())) {
  418. throw new CompileException("cannot convert type: "
  419. + value.getClass() + ": to " + meth.getParameterTypes()[0], expr, start);
  420. }
  421. dataConversion(getWrapperClass(targetType));
  422. if (targetType.isPrimitive()) {
  423. unwrapPrimitive(targetType);
  424. }
  425. else checkcast(targetType);
  426. meth.invoke(ctx, convert(value, meth.getParameterTypes()[0]));
  427. }
  428. else {
  429. if (targetType.isPrimitive()) {
  430. if (value == null) value = PropertyTools.getPrimitiveInitialValue(targetType);
  431. jmp = new Label();
  432. assert debug("IFNOTNULL jmp");
  433. mv.visitJumpInsn(IFNONNULL, jmp);
  434. assert debug("ICONST_0");
  435. mv.visitInsn(ICONST_0);
  436. assert debug("INVOKEVIRTUAL " + getInternalName(meth.getDeclaringClass()) + "." + meth.getName());
  437. mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(meth.getDeclaringClass()), meth.getName(),
  438. getMethodDescriptor(meth));
  439. assert debug("GOTO jmp2");
  440. mv.visitJumpInsn(GOTO, jmp2);
  441. assert debug("jmp:");
  442. mv.visitLabel(jmp);
  443. assert debug("ALOAD 4");
  444. mv.visitVarInsn(ALOAD, 4);
  445. unwrapPrimitive(targetType);
  446. }
  447. else {
  448. checkcast(targetType);
  449. }
  450. meth.invoke(ctx, value);
  451. }
  452. assert debug("INVOKEVIRTUAL " + getInternalName(meth.getDeclaringClass()) + "." + meth.getName());
  453. mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(meth.getDeclaringClass()), meth.getName(),
  454. getMethodDescriptor(meth));
  455. assert debug("jmp2:");
  456. mv.visitLabel(jmp2);
  457. assert debug("ALOAD 4");
  458. mv.visitVarInsn(ALOAD, 4);
  459. }
  460. else if (ctx instanceof Map) {
  461. assert debug("CHECKCAST " + getInternalName(ctx.getClass()));
  462. mv.visitTypeInsn(CHECKCAST, getInternalName(ctx.getClass()));
  463. assert debug("LDC '" + tk + "'");
  464. mv.visitLdcInsn(tk);
  465. assert debug("ALOAD 4");
  466. mv.visitVarInsn(ALOAD, 4);
  467. assert debug("INVOKEVIRTUAL java/util/HashMap.put");
  468. mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
  469. assert debug("ALOAD 4");
  470. mv.visitVarInsn(ALOAD, 4);
  471. //noinspection unchecked
  472. ((Map) ctx).put(tk, value);
  473. }
  474. else {
  475. throw new PropertyAccessException("could not access property (" + tk + ") in: "
  476. + ingressType.getName(), expr, start);
  477. }
  478. }
  479. catch (InvocationTargetException e) {
  480. throw new PropertyAccessException("could not access property", expr, start, e);
  481. }
  482. catch (IllegalAccessException e) {
  483. throw new PropertyAccessException("could not access property", expr, start, e);
  484. }
  485. try {
  486. deferFinish = false;
  487. noinit = false;
  488. _finishJIT();
  489. return _initializeAccessor();
  490. }
  491. catch (Exception e) {
  492. throw new CompileException("could not generate accessor", expr, start, e);
  493. }
  494. }
  495. private void _finishJIT() {
  496. if (deferFinish) {
  497. return;
  498. }
  499. if (returnType != null && returnType.isPrimitive()) {
  500. //noinspection unchecked
  501. wrapPrimitive(returnType);
  502. }
  503. if (returnType == void.class) {
  504. assert debug("ACONST_NULL");
  505. mv.visitInsn(ACONST_NULL);
  506. }
  507. assert debug("ARETURN");
  508. mv.visitInsn(ARETURN);
  509. assert debug("\n{METHOD STATS (maxstack=" + stacksize + ")}\n");
  510. dumpAdvancedDebugging(); // dump advanced debugging if necessary
  511. mv.visitMaxs(stacksize, maxlocals);
  512. mv.visitEnd();
  513. mv = cw.visitMethod(ACC_PUBLIC, "getKnownEgressType", "()Ljava/lang/Class;", null, null);
  514. mv.visitCode();
  515. visitConstantClass(returnType);
  516. mv.visitInsn(ARETURN);
  517. mv.visitMaxs(1, 1);
  518. mv.visitEnd();
  519. if (propNull) {
  520. cw.visitField(ACC_PUBLIC, "nullPropertyHandler", "L" + NAMESPACE + "integration/PropertyHandler;", null, null).visitEnd();
  521. }
  522. if (methNull) {
  523. cw.visitField(ACC_PUBLIC, "nullMethodHandler", "L" + NAMESPACE + "integration/PropertyHandler;", null, null).visitEnd();
  524. }
  525. buildInputs();
  526. if (buildLog != null && buildLog.length() != 0 && expr != null) {
  527. mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
  528. mv.visitCode();
  529. Label l0 = new Label();
  530. mv.visitLabel(l0);
  531. mv.visitLdcInsn(buildLog.toString() + "\n\n## { " + new String(expr) + " }");
  532. mv.visitInsn(ARETURN);
  533. Label l1 = new Label();
  534. mv.visitLabel(l1);
  535. mv.visitMaxs(1, 1);
  536. mv.visitEnd();
  537. }
  538. cw.visitEnd();
  539. }
  540. private void visitConstantClass(Class<?> clazz) {
  541. if (clazz == null) clazz = Object.class;
  542. if (clazz.isPrimitive()) {
  543. mv.visitFieldInsn(GETSTATIC, toNonPrimitiveType(clazz).getName().replace(".", "/"), "TYPE", "Ljava/lang/Class;");
  544. } else {
  545. mv.visitLdcInsn(org.mvel2.asm.Type.getType(clazz));
  546. }
  547. }
  548. private Accessor _initializeAccessor() throws Exception {
  549. if (deferFinish) {
  550. return null;
  551. }
  552. /**
  553. * Hot load the class we just generated.
  554. */
  555. Class cls = loadClass(className, cw.toByteArray());
  556. assert debug("[MVEL JIT Completed Optimization <<" + (expr != null ? new String(expr) : "") + ">>]::" + cls
  557. + " (time: " + (System.currentTimeMillis() - time) + "ms)");
  558. Object o;
  559. try {
  560. if (compiledInputs.size() == 0) {
  561. o = cls.newInstance();
  562. }
  563. else {
  564. Class[] parms = new Class[compiledInputs.size()];
  565. for (int i = 0; i < compiledInputs.size(); i++) {
  566. parms[i] = ExecutableStatement.class;
  567. }
  568. o = cls.getConstructor(parms).newInstance(compiledInputs.toArray(new ExecutableStatement[compiledInputs.size()]));
  569. }
  570. if (propNull) cls.getField("nullPropertyHandler").set(o, getNullPropertyHandler());
  571. if (methNull) cls.getField("nullMethodHandler").set(o, getNullMethodHandler());
  572. }
  573. catch (VerifyError e) {
  574. System.out.println("**** COMPILER BUG! REPORT THIS IMMEDIATELY AT http://jira.codehaus.org/browse/mvel2");
  575. System.out.println("Expression: " + (expr == null ? null : new String(expr)));
  576. throw e;
  577. }
  578. return (Accessor) o;
  579. }
  580. private Accessor compileAccessor() {
  581. assert debug("<<INITIATE COMPILE>>");
  582. Object curr = ctx;
  583. try {
  584. if (!MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING) {
  585. while (cursor < end) {
  586. switch (nextSubToken()) {
  587. case BEAN:
  588. curr = getBeanProperty(curr, capture());
  589. break;
  590. case METH:
  591. curr = getMethod(curr, capture());
  592. break;
  593. case COL:
  594. curr = getCollectionProperty(curr, capture());
  595. break;
  596. case WITH:
  597. curr = getWithProperty(curr);
  598. break;
  599. }
  600. // check to see if a null safety is enabled on this property.
  601. if (fields == -1) {
  602. if (curr == null) {
  603. if (nullSafe) {
  604. throw new OptimizationNotSupported();
  605. }
  606. break;
  607. }
  608. else {
  609. fields = 0;
  610. }
  611. }
  612. first = false;
  613. if (nullSafe && cursor < end) {
  614. assert debug("DUP");
  615. mv.visitInsn(DUP);
  616. Label j = new Label();
  617. assert debug("IFNONNULL : jump");
  618. mv.visitJumpInsn(IFNONNULL, j);
  619. assert debug("ARETURN");
  620. mv.visitInsn(ARETURN);
  621. assert debug("LABEL:jump");
  622. mv.visitLabel(j);
  623. }
  624. }
  625. }
  626. else {
  627. while (cursor < end) {
  628. switch (nextSubToken()) {
  629. case BEAN:
  630. curr = getBeanPropertyAO(curr, capture());
  631. break;
  632. case METH:
  633. curr = getMethod(curr, capture());
  634. break;
  635. case COL:
  636. curr = getCollectionPropertyAO(curr, capture());
  637. break;
  638. case WITH:
  639. curr = getWithProperty(curr);
  640. break;
  641. }
  642. // check to see if a null safety is enabled on this property.
  643. if (fields == -1) {
  644. if (curr == null) {
  645. if (nullSafe) {
  646. throw new OptimizationNotSupported();
  647. }
  648. break;
  649. }
  650. else {
  651. fields = 0;
  652. }
  653. }
  654. first = false;
  655. if (nullSafe && cursor < end) {
  656. assert debug("DUP");
  657. mv.visitInsn(DUP);
  658. Label j = new Label();
  659. assert debug("IFNONNULL : jump");
  660. mv.visitJumpInsn(IFNONNULL, j);
  661. assert debug("ARETURN");
  662. mv.visitInsn(ARETURN);
  663. assert debug("LABEL:jump");
  664. mv.visitLabel(j);
  665. }
  666. }
  667. }
  668. val = curr;
  669. _finishJIT();
  670. return _initializeAccessor();
  671. }
  672. catch (InvocationTargetException e) {
  673. throw new PropertyAccessException(new String(expr), expr, st, e);
  674. }
  675. catch (IllegalAccessException e) {
  676. throw new PropertyAccessException(new String(expr), expr, st, e);
  677. }
  678. catch (IndexOutOfBoundsException e) {
  679. throw new PropertyAccessException(new String(expr), expr, st, e);
  680. }
  681. catch (PropertyAccessException e) {
  682. throw new CompileException(e.getMessage(), expr, st, e);
  683. }
  684. catch (CompileException e) {
  685. throw e;
  686. }
  687. catch (NullPointerException e) {
  688. throw new PropertyAccessException(new String(expr), expr, st, e);
  689. }
  690. catch (OptimizationNotSupported e) {
  691. throw e;
  692. }
  693. catch (Exception e) {
  694. throw new CompileException(e.getMessage(), expr, st, e);
  695. }
  696. }
  697. private Object getWithProperty(Object ctx) {
  698. assert debug("\n ** ENTER -> {with}");
  699. if (first) {
  700. assert debug("ALOAD 1");
  701. mv.visitVarInsn(ALOAD, 1);
  702. first = false;
  703. }
  704. String root = new String(expr, 0, cursor - 1).trim();
  705. int start = cursor + 1;
  706. cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '{', pCtx);
  707. this.returnType = ctx != null ? ctx.getClass() : null;
  708. for (WithNode.ParmValuePair aPvp : WithNode.compileWithExpressions(expr, start, cursor++ - start, root, ingressType, pCtx)) {
  709. assert debug("DUP");
  710. mv.visitInsn(DUP);
  711. assert debug("ASTORE " + (5 + compileDepth) + " (withctx)");
  712. mv.visitVarInsn(ASTORE, 5 + compileDepth);
  713. aPvp.eval(ctx, variableFactory);
  714. if (aPvp.getSetExpression() == null) {
  715. addSubstatement(aPvp.getStatement());
  716. }
  717. else {
  718. compiledInputs.add((ExecutableStatement) aPvp.getSetExpression());
  719. // load set expression
  720. assert debug("ALOAD 0");
  721. mv.visitVarInsn(ALOAD, 0);
  722. assert debug("GETFIELD p" + (compiledInputs.size() - 1));
  723. mv.visitFieldInsn(GETFIELD, className, "p" + (compiledInputs.size() - 1), "L" + NAMESPACE
  724. + "compiler/ExecutableStatement;");
  725. // ctx
  726. assert debug("ALOAD " + (5 + compileDepth) + "(withctx)");
  727. mv.visitVarInsn(ALOAD, (5 + compileDepth));
  728. // elCtx
  729. assert debug("ALOAD 2");
  730. mv.visitVarInsn(ALOAD, 2);
  731. // variable factory
  732. assert debug("ALOAD 3");
  733. mv.visitVarInsn(ALOAD, 3);
  734. // the value to set.
  735. addSubstatement(aPvp.getStatement());
  736. assert debug("INVOKEINTERFACE Accessor.setValue");
  737. mv.visitMethodInsn(INVOKEINTERFACE, NAMESPACE + "compiler/ExecutableStatement",
  738. "setValue",
  739. "(Ljava/lang/Object;Ljava/lang/Object;L"
  740. + NAMESPACE + "integration/VariableResolverFactory;Ljava/lang/Object;)Ljava/lang/Object;");
  741. assert debug("POP");
  742. mv.visitInsn(POP);
  743. }
  744. }
  745. return ctx;
  746. }
  747. private Object getBeanPropertyAO(Object ctx, String property)
  748. throws IllegalAccessException, InvocationTargetException {
  749. if (ctx != null && hasPropertyHandler(ctx.getClass())) {
  750. return propHandlerByteCode(property, ctx, ctx.getClass());
  751. }
  752. return getBeanProperty(ctx, property);
  753. }
  754. private Object getBeanProperty(Object ctx, String property)
  755. throws IllegalAccessException, InvocationTargetException {
  756. assert debug("\n ** ENTER -> {bean: " + property + "; ctx=" + ctx + "}");
  757. if ((pCtx == null ? currType : pCtx.getVarOrInputTypeOrNull(property)) == Object.class
  758. && !pCtx.isStrongTyping()) {
  759. currType = null;
  760. }
  761. if (returnType != null && returnType.isPrimitive()) {
  762. //noinspection unchecked
  763. wrapPrimitive(returnType);
  764. }
  765. boolean classRef = false;
  766. Class<?> cls;
  767. if (ctx instanceof Class) {
  768. if (MVEL.COMPILER_OPT_SUPPORT_JAVA_STYLE_CLASS_LITERALS
  769. && "class".equals(property)) {
  770. ldcClassConstant((Class<?>) ctx);
  771. return ctx;
  772. }
  773. cls = (Class<?>) ctx;
  774. classRef = true;
  775. }
  776. else if (ctx != null) {
  777. cls = ctx.getClass();
  778. }
  779. else {
  780. cls = null;
  781. }
  782. if (hasPropertyHandler(cls)) {
  783. PropertyHandler prop = getPropertyHandler(cls);
  784. if (prop instanceof ProducesBytecode) {
  785. ((ProducesBytecode) prop).produceBytecodeGet(mv, property, variableFactory);
  786. return prop.getProperty(property, ctx, variableFactory);
  787. }
  788. else {
  789. throw new RuntimeException("unable to compileShared: custom accessor does not support producing bytecode: "
  790. + prop.getClass().getName());
  791. }
  792. }
  793. Member member = cls != null ? getFieldOrAccessor(cls, property) : null;
  794. if (member != null && classRef && (member.getModifiers() & Modifier.STATIC) == 0) {
  795. member = null;
  796. }
  797. if (member != null && hasGetListeners()) {
  798. mv.visitVarInsn(ALOAD, 1);
  799. mv.visitLdcInsn(member.getName());
  800. mv.visitVarInsn(ALOAD, 3);
  801. mv.visitMethodInsn(INVOKESTATIC, NAMESPACE + "integration/GlobalListenerFactory", "notifyGetListeners",
  802. "(Ljava/lang/Object;Ljava/lang/String;L" + NAMESPACE + "integration/VariableResolverFactory;)V");
  803. notifyGetListeners(ctx, member.getName(), variableFactory);
  804. }
  805. if (first) {
  806. if ("this".equals(property)) {
  807. assert debug("ALOAD 2");
  808. mv.visitVarInsn(ALOAD, 2);
  809. return thisRef;
  810. }
  811. else if (variableFactory != null && variableFactory.isResolveable(property)) {
  812. if (variableFactory.isIndexedFactory() && variableFactory.isTarget(property)) {
  813. int idx;
  814. try {
  815. loadVariableByIndex(idx = variableFactory.variableIndexOf(property));
  816. }
  817. catch (Exception e) {
  818. throw new OptimizationFailure(property);
  819. }
  820. return variableFactory.getIndexedVariableResolver(idx).getValue();
  821. }
  822. else {
  823. try {
  824. loadVariableByName(property);
  825. }
  826. catch (Exception e) {
  827. throw new OptimizationFailure("critical error in JIT", e);
  828. }
  829. return variableFactory.getVariableResolver(property).getValue();
  830. }
  831. }
  832. else {
  833. assert debug("ALOAD 1");
  834. mv.visitVarInsn(ALOAD, 1);
  835. }
  836. }
  837. if (member instanceof Field) {
  838. Object o = ((Field) member).get(ctx);
  839. if (((member.getModifiers() & STATIC) != 0)) {
  840. // Check if the static field reference is a constant and a primitive.
  841. if ((member.getModifiers() & FINAL) != 0 && (o instanceof String || ((Field) member).getType().isPrimitive())) {
  842. o = ((Field) member).get(null);
  843. assert debug("LDC " + valueOf(o));
  844. mv.visitLdcInsn(o);
  845. wrapPrimitive(o.getClass());
  846. if (hasNullPropertyHandler()) {
  847. if (o == null) {
  848. o = getNullPropertyHandler().getProperty(member.getName(), ctx, variableFactory);
  849. }
  850. writeOutNullHandler(member, 0);
  851. }
  852. return o;
  853. }
  854. else {
  855. assert debug("GETSTATIC " + getDescriptor(member.getDeclaringClass()) + "."
  856. + member.getName() + "::" + getDescriptor(((Field) member).getType()));
  857. mv.visitFieldInsn(GETSTATIC, getInternalName(member.getDeclaringClass()),
  858. member.getName(), getDescriptor(returnType = ((Field) member).getType()));
  859. }
  860. }
  861. else {
  862. assert debug("CHECKCAST " + getInternalName(cls));
  863. mv.visitTypeInsn(CHECKCAST, getInternalName(cls));
  864. assert debug("GETFIELD " + property + ":" + getDescriptor(((Field) member).getType()));
  865. mv.visitFieldInsn(GETFIELD, getInternalName(cls), property, getDescriptor(returnType = ((Field) member)
  866. .getType()));
  867. }
  868. returnType = ((Field) member).getType();
  869. if (hasNullPropertyHandler()) {
  870. if (o == null) {
  871. o = getNullPropertyHandler().getProperty(member.getName(), ctx, variableFactory);
  872. }
  873. writeOutNullHandler(member, 0);
  874. }
  875. currType = toNonPrimitiveType(returnType);
  876. return o;
  877. }
  878. else if (member != null) {
  879. Object o;
  880. if (first) {
  881. assert debug("ALOAD 1 (B)");
  882. mv.visitVarInsn(ALOAD, 1);
  883. }
  884. try {
  885. o = ((Method) member).invoke(ctx, EMPTYARG);
  886. if (returnType != member.getDeclaringClass()) {
  887. assert debug("CHECKCAST " + getInternalName(member.getDeclaringClass()));
  888. mv.visitTypeInsn(CHECKCAST, getInternalName(member.getDeclaringClass()));
  889. }
  890. returnType = ((Method) member).getReturnType();
  891. assert debug("INVOKEVIRTUAL " + member.getName() + ":" + returnType);
  892. mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(member.getDeclaringClass()), member.getName(),
  893. getMethodDescriptor((Method) member));
  894. }
  895. catch (IllegalAccessException e) {
  896. Method iFaceMeth = determineActualTargetMethod((Method) member);
  897. if (iFaceMeth == null)
  898. throw new PropertyAccessException("could not access field: " + cls.getName() + "." + property, expr, st, e);
  899. assert debug("CHECKCAST " + getInternalName(iFaceMeth.getDeclaringClass()));
  900. mv.visitTypeInsn(CHECKCAST, getInternalName(iFaceMeth.getDeclaringClass()));
  901. returnType = iFaceMeth.getReturnType();
  902. assert debug("INVOKEINTERFACE " + member.getName() + ":" + returnType);
  903. mv.visitMethodInsn(INVOKEINTERFACE, getInternalName(iFaceMeth.getDeclaringClass()), member.getName(),
  904. getMethodDescriptor((Method) member));
  905. o = iFaceMeth.invoke(ctx, EMPTYARG);
  906. }
  907. catch (IllegalArgumentException e) {
  908. if (member.getDeclaringClass().equals(ctx)) {
  909. try {
  910. Class c = Class.forName(member.getDeclaringClass().getName() + "$" + property);
  911. throw new CompileException("name collision between innerclass: " + c.getCanonicalName()
  912. + "; and bean accessor: " + property + " (" + member.toString() + ")", expr, tkStart);
  913. }
  914. catch (ClassNotFoundException e2) {
  915. //fallthru
  916. }
  917. }
  918. throw e;
  919. }
  920. if (hasNullPropertyHandler()) {
  921. if (o == null) o = getNullPropertyHandler().getProperty(member.getName(), ctx, variableFactory);
  922. writeOutNullHandler(member, 0);
  923. }
  924. currType = toNonPrimitiveType(returnType);
  925. return o;
  926. }
  927. else if (ctx instanceof Map && (((Map) ctx).containsKey(property) || nullSafe)) {
  928. assert debug("CHECKCAST java/util/Map");
  929. mv.visitTypeInsn(CHECKCAST, "java/util/Map");
  930. assert debug("LDC: \"" + property + "\"");
  931. mv.visitLdcInsn(property);
  932. assert debug("INVOKEINTERFACE: get");
  933. mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
  934. return ((Map) ctx).get(property);
  935. }
  936. else if (first && "this".equals(property)) {
  937. assert debug("ALOAD 2");
  938. mv.visitVarInsn(ALOAD, 2); // load the thisRef value.
  939. return this.thisRef;
  940. }
  941. else if ("length".equals(property) && ctx.getClass().isArray()) {
  942. anyArrayCheck(ctx.getClass());
  943. assert debug("ARRAYLENGTH");
  944. mv.visitInsn(ARRAYLENGTH);
  945. wrapPrimitive(int.class);
  946. return getLength(ctx);
  947. }
  948. else if (LITERALS.containsKey(property)) {
  949. Object lit = LITERALS.get(property);
  950. if (lit instanceof Class) {
  951. ldcClassConstant((Class) lit);
  952. }
  953. return lit;
  954. }
  955. else {
  956. Object ts = tryStaticAccess();
  957. if (ts != null) {
  958. if (ts instanceof Class) {
  959. ldcClassConstant((Class) ts);
  960. return ts;
  961. }
  962. else if (ts instanceof Method) {
  963. writeFunctionPointerStub(((Method) ts).getDeclaringClass(), (Method) ts);
  964. return ts;
  965. }
  966. else {
  967. Field f = (Field) ts;
  968. if ((f.getModifiers() & FINAL) != 0) {
  969. Object finalVal = f.get(null);
  970. assert debug("LDC " + valueOf(finalVal));
  971. mv.visitLdcInsn(finalVal);
  972. wrapPrimitive(finalVal.getClass());
  973. return finalVal;
  974. }
  975. else {
  976. assert debug("GETSTATIC " + getInternalName(f.getDeclaringClass()) + "."
  977. + ((Field) ts).getName() + "::" + getDescriptor(f.getType()));
  978. mv.visitFieldInsn(GETSTATIC, getInternalName(f.getDeclaringClass()),
  979. f.getName(), getDescriptor(returnType = f.getType()));
  980. return f.get(null);
  981. }
  982. }
  983. }
  984. else if (ctx instanceof Class) {
  985. /**
  986. * This is our ugly support for function pointers. This works but needs to be re-thought out at some
  987. * point.
  988. */
  989. Class c = (Class) ctx;
  990. for (Method m : c.getMethods()) {
  991. if (property.equals(m.getName())) {
  992. if (MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL) {
  993. assert debug("POP");
  994. mv.visitInsn(POP);
  995. assert debug("INVOKESTATIC " + m.getName());
  996. mv.visitMethodInsn(INVOKESTATIC, getInternalName(m.getDeclaringClass()), m.getName(),
  997. getMethodDescriptor(m));
  998. returnType = m.getReturnType();
  999. return m.invoke(null, EMPTY_OBJ_ARR);
  1000. }
  1001. else {
  1002. writeFunctionPointerStub(c, m);
  1003. return m;
  1004. }
  1005. }
  1006. }
  1007. try {
  1008. Class subClass = findClass(variableFactory, c.getName() + "$" + property, pCtx);
  1009. ldcClassConstant(subClass);
  1010. return subClass;
  1011. }
  1012. catch (ClassNotFoundException cnfe) {
  1013. // fall through.
  1014. }
  1015. }
  1016. else if (MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL) {
  1017. return getMethod(ctx, property);
  1018. }
  1019. if (ctx == null) {
  1020. throw new PropertyAccessException("unresolvable property or identifier: " + property, expr, st);
  1021. }
  1022. else {
  1023. throw new PropertyAccessException("could not access: " + property + "; in class: "
  1024. + ctx.getClass().getName(), expr, st);
  1025. }
  1026. }
  1027. }
  1028. private void writeFunctionPointerStub(Class c, Method m) {
  1029. ldcClassConstant(c);
  1030. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethods", "()[Ljava/lang/reflect/Method;");
  1031. mv.visitVarInsn(ASTORE, 7);
  1032. mv.visitInsn(ICONST_0);
  1033. mv.visitVarInsn(ISTORE, 5);
  1034. mv.visitVarInsn(ALOAD, 7);
  1035. mv.visitInsn(ARRAYLENGTH);
  1036. mv.visitVarInsn(ISTORE, 6);
  1037. Label l1 = new Label();
  1038. mv.visitJumpInsn(GOTO, l1);
  1039. Label l2 = new Label();
  1040. mv.visitLabel(l2);
  1041. mv.visitVarInsn(ALOAD, 7);
  1042. mv.visitVarInsn(ILOAD, 5);
  1043. mv.visitInsn(AALOAD);
  1044. mv.visitVarInsn(ASTORE, 4);
  1045. Label l3 = new Label();
  1046. mv.visitLabel(l3);
  1047. mv.visitLdcInsn(m.getName());
  1048. mv.visitVarInsn(ALOAD, 4);
  1049. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "getName", "()Ljava/lang/String;");
  1050. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
  1051. Label l4 = new Label();
  1052. mv.visitJumpInsn(IFEQ, l4);
  1053. Label l5 = new Label();
  1054. mv.visitLabel(l5);
  1055. mv.visitVarInsn(ALOAD, 4);
  1056. mv.visitInsn(ARETURN);
  1057. mv.visitLabel(l4);
  1058. mv.visitIincInsn(5, 1);
  1059. mv.visitLabel(l1);
  1060. mv.visitVarInsn(ILOAD, 5);
  1061. mv.visitVarInsn(ILOAD, 6);
  1062. mv.visitJumpInsn(IF_ICMPLT, l2);
  1063. Label l6 = new Label();
  1064. mv.visitLabel(l6);
  1065. mv.visitInsn(ACONST_NULL);
  1066. mv.visitInsn(ARETURN);
  1067. // deferFinish = true;
  1068. }
  1069. private Object getCollectionProperty(Object ctx, String prop)
  1070. throws IllegalAccessException, InvocationTargetException {
  1071. if (prop.trim().length() > 0) {
  1072. ctx = getBeanProperty(ctx, prop);
  1073. first = false;
  1074. }
  1075. currType = null;
  1076. if (ctx == null) return null;
  1077. assert debug("\n ** ENTER -> {collection:<<" + prop + ">>; ctx=" + ctx + "}");
  1078. if (first) {
  1079. assert debug("ALOAD 1");
  1080. mv.visitVarInsn(ALOAD, 1);
  1081. }
  1082. int start = ++cursor;
  1083. skipWhitespace();
  1084. if (cursor == end)
  1085. throw new CompileException("unterminated '['", expr, st);
  1086. if (scanTo(']'))
  1087. throw new CompileException("unterminated '['", expr, st);
  1088. String tk = new String(expr, start, cursor - start);
  1089. assert debug("{collection token: [" + tk + "]}");
  1090. ExecutableStatement compiled = (ExecutableStatement) subCompileExpression(tk.toCharArray(), pCtx);
  1091. Object item = compiled.getValue(ctx, variableFactory);
  1092. ++cursor;
  1093. if (ctx instanceof Map) {
  1094. assert debug("CHECKCAST java/util/Map");
  1095. mv.visitTypeInsn(CHECKCAST, "java/util/Map");
  1096. Class c = writeLiteralOrSubexpression(compiled);
  1097. if (c != null && c.isPrimitive()) {
  1098. wrapPrimitive(c);
  1099. }
  1100. assert debug("INVOKEINTERFACE: get");
  1101. mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
  1102. return ((Map) ctx).get(item);
  1103. }
  1104. else if (ctx instanceof List) {
  1105. assert debug("CHECKCAST java/util/List");
  1106. mv.visitTypeInsn(CHECKCAST, "java/util/List");
  1107. writeLiteralOrSubexpression(compiled, int.class);
  1108. assert debug("INVOKEINTERFACE: java/util/List.get");
  1109. mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;");
  1110. return ((List) ctx).get(convert(item, Integer.class));
  1111. }
  1112. else if (ctx.getClass().isArray()) {
  1113. assert debug("CHECKCAST " + getDescriptor(ctx.getClass()));
  1114. mv.visitTypeInsn(CHECKCAST, getDescriptor(ctx.getClass()));
  1115. writeLiteralOrSubexpression(compiled, int.class, item.getClass());
  1116. Class cls = getBaseComponentType(ctx.getClass());
  1117. if (cls.isPrimitive()) {
  1118. if (cls == int.class) {
  1119. assert debug("IALOAD");
  1120. mv.visitInsn(IALOAD);
  1121. }
  1122. else if (cls == char.class) {
  1123. assert debug("CALOAD");
  1124. mv.visitInsn(CALOAD);
  1125. }
  1126. else if (cls == boolean.class) {
  1127. assert debug("BALOAD");
  1128. mv.visitInsn(BALOAD);
  1129. }
  1130. else if (cls == double.class) {
  1131. assert debug("DALOAD");
  1132. mv.visitInsn(DALOAD);
  1133. }
  1134. else if (cls == float.class) {
  1135. assert debug("FALOAD");
  1136. mv.visitInsn(FALOAD);
  1137. }
  1138. else if (cls == short.class) {
  1139. assert debug("SALOAD");
  1140. mv.visitInsn(SALOAD);
  1141. }
  1142. else if (cls == long.class) {
  1143. assert debug("LALOAD");
  1144. mv.visitInsn(LALOAD);
  1145. }
  1146. else if (cls == byte.class) {
  1147. assert debug("BALOAD");
  1148. mv.visitInsn(BALOAD);
  1149. }
  1150. wrapPrimitive(cls);
  1151. }
  1152. else {
  1153. assert debug("AALOAD");
  1154. mv.visitInsn(AALOAD);
  1155. }
  1156. return Array.get(ctx, convert(item, Integer.class));
  1157. }
  1158. else if (ctx instanceof CharSequence) {
  1159. assert debug("CHECKCAST java/lang/CharSequence");
  1160. mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence");
  1161. if (item instanceof Integer) {
  1162. intPush((Integer) item);
  1163. assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
  1164. mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "charAt", "(I)C");
  1165. wrapPrimitive(char.class);
  1166. return ((CharSequence) ctx).charAt((Integer) item);
  1167. }
  1168. else {
  1169. writeLiteralOrSubexpression(compiled, Integer.class);
  1170. unwrapPrimitive(int.class);
  1171. assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
  1172. mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "charAt", "(I)C");
  1173. wrapPrimitive(char.class);
  1174. return ((CharSequence) ctx).charAt(convert(item, Integer.class));
  1175. }
  1176. }
  1177. else {
  1178. TypeDescriptor tDescr = new TypeDescriptor(expr, this.start, length, 0);
  1179. if (tDescr.isArray()) {
  1180. try {
  1181. Class cls = getClassReference((Class) ctx, tDescr, variableFactory, pCtx);
  1182. // rootNode = new StaticReferenceAccessor(cls);
  1183. ldcClassConstant(cls);
  1184. return cls;
  1185. }
  1186. catch (Exception e) {
  1187. //fall through
  1188. }
  1189. }
  1190. throw new CompileException("illegal use of []: unknown type: "
  1191. + (ctx == null ? null : ctx.getClass().getName()), expr, st);
  1192. }
  1193. }
  1194. private Object getCollectionPropertyAO(Object ctx, String prop)
  1195. throws IllegalAccessException, InvocationTargetException {
  1196. if (prop.length() > 0) {
  1197. ctx = getBeanProperty(ctx, prop);
  1198. first = false;
  1199. }
  1200. currType = null;
  1201. if (ctx == null) return null;
  1202. assert debug("\n ** ENTER -> {collection:<<" + prop + ">>; ctx=" + ctx + "}");
  1203. int _start = ++cursor;
  1204. skipWhitespace();
  1205. if (cursor == end)
  1206. throw new CompileException("unterminated '['", expr, st);
  1207. if (scanTo(']'))
  1208. throw new CompileException("unterminated '['", expr, st);
  1209. String tk = new String(expr, _start, cursor - _start);
  1210. assert debug("{collection token:<<" + tk + ">>}");
  1211. ExecutableStatement compiled = (ExecutableStatement) subCompileExpression(tk.toCharArray());
  1212. Object item = compiled.getValue(ctx, variableFactory);
  1213. ++cursor;
  1214. if (ctx instanceof Map) {
  1215. if (hasPropertyHandler(Map.class)) {
  1216. return propHandlerByteCode(tk, ctx, Map.class);
  1217. }
  1218. else {
  1219. if (first) {
  1220. assert debug("ALOAD 1");
  1221. mv.visitVarInsn(ALOAD, 1);
  1222. }
  1223. assert debug("CHECKCAST java/util/Map");
  1224. mv.visitTypeInsn(CHECKCAST, "java/util/Map");
  1225. Class c = writeLiteralOrSubexpression(compiled);
  1226. if (c != null && c.isPrimitive()) {
  1227. wrapPrimitive(c);
  1228. }
  1229. assert debug("INVOKEINTERFACE: Map.get");
  1230. mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
  1231. }
  1232. return ((Map) ctx).get(item);
  1233. }
  1234. else if (ctx instanceof List) {
  1235. if (hasPropertyHandler(List.class)) {
  1236. return propHandlerByteCode(tk, ctx, List.class);
  1237. }
  1238. else {
  1239. if (first) {
  1240. assert debug("ALOAD 1");
  1241. mv.visitVarInsn(ALOAD, 1);
  1242. }
  1243. assert debug("CHECKCAST java/util/List");
  1244. mv.visitTypeInsn(CHECKCAST, "java/util/List");
  1245. writeLiteralOrSubexpression(compiled, int.class);
  1246. assert debug("INVOKEINTERFACE: java/util/List.get");
  1247. mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;");
  1248. return ((List) ctx).get(convert(item, Integer.class));
  1249. }
  1250. }
  1251. else if (ctx.getClass().isArray()) {
  1252. if (hasPropertyHandler(Array.class)) {
  1253. return propHandlerByteCode(tk, ctx, Array.class);
  1254. }
  1255. else {
  1256. if (first) {
  1257. assert debug("ALOAD 1");
  1258. mv.visitVarInsn(ALOAD, 1);
  1259. }
  1260. assert debug("CHECKCAST " + getDescriptor(ctx.getClass()));
  1261. mv.visitTypeInsn(CHECKCAST, getDescriptor(ctx.getClass()));
  1262. writeLiteralOrSubexpression(compiled, int.class, item.getClass());

Large files files are truncated, but you can click here to view the full file