PageRenderTime 39ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  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());
  1263. Class cls = getBaseComponentType(ctx.getClass());
  1264. if (cls.isPrimitive()) {
  1265. if (cls == int.class) {
  1266. assert debug("IALOAD");
  1267. mv.visitInsn(IALOAD);
  1268. }
  1269. else if (cls == char.class) {
  1270. assert debug("CALOAD");
  1271. mv.visitInsn(CALOAD);
  1272. }
  1273. else if (cls == boolean.class) {
  1274. assert debug("BALOAD");
  1275. mv.visitInsn(BALOAD);
  1276. }
  1277. else if (cls == double.class) {
  1278. assert debug("DALOAD");
  1279. mv.visitInsn(DALOAD);
  1280. }
  1281. else if (cls == float.class) {
  1282. assert debug("FALOAD");
  1283. mv.visitInsn(FALOAD);
  1284. }
  1285. else if (cls == short.class) {
  1286. assert debug("SALOAD");
  1287. mv.visitInsn(SALOAD);
  1288. }
  1289. else if (cls == long.class) {
  1290. assert debug("LALOAD");
  1291. mv.visitInsn(LALOAD);
  1292. }
  1293. else if (cls == byte.class) {
  1294. assert debug("BALOAD");
  1295. mv.visitInsn(BALOAD);
  1296. }
  1297. wrapPrimitive(cls);
  1298. }
  1299. else {
  1300. assert debug("AALOAD");
  1301. mv.visitInsn(AALOAD);
  1302. }
  1303. return Array.get(ctx, convert(item, Integer.class));
  1304. }
  1305. }
  1306. else if (ctx instanceof CharSequence) {
  1307. if (hasPropertyHandler(CharSequence.class)) {
  1308. return propHandlerByteCode(tk, ctx, CharSequence.class);
  1309. }
  1310. else {
  1311. if (first) {
  1312. assert debug("ALOAD 1");
  1313. mv.visitVarInsn(ALOAD, 1);
  1314. }
  1315. assert debug("CHECKCAST java/lang/CharSequence");
  1316. mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence");
  1317. if (item instanceof Integer) {
  1318. intPush((Integer) item);
  1319. assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
  1320. mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "charAt", "(I)C");
  1321. wrapPrimitive(char.class);
  1322. return ((CharSequence) ctx).charAt((Integer) item);
  1323. }
  1324. else {
  1325. writeLiteralOrSubexpression(compiled, Integer.class);
  1326. unwrapPrimitive(int.class);
  1327. assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
  1328. mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "charAt", "(I)C");
  1329. wrapPrimitive(char.class);
  1330. return ((CharSequence) ctx).charAt(convert(item, Integer.class));
  1331. }
  1332. }
  1333. }
  1334. else {
  1335. TypeDescriptor tDescr = new TypeDescriptor(expr, start, end - start, 0);
  1336. if (tDescr.isArray()) {
  1337. try {
  1338. Class cls = getClassReference((Class) ctx, tDescr, variableFactory, pCtx);
  1339. // rootNode = new StaticReferenceAccessor(cls);
  1340. ldcClassConstant(cls);
  1341. return cls;
  1342. }
  1343. catch (Exception e) {
  1344. //fall through
  1345. }
  1346. }
  1347. throw new CompileException("illegal use of []: unknown type: "
  1348. + (ctx == null ? null : ctx.getClass().getName()), expr, st);
  1349. }
  1350. }
  1351. @SuppressWarnings({"unchecked"})
  1352. private Object getMethod(Object ctx, String name)
  1353. throws IllegalAccessException, InvocationTargetException {
  1354. assert debug("\n ** {method: " + name + "}");
  1355. int st = cursor;
  1356. String tk = cursor != end && expr[cursor] == '(' && ((cursor = balancedCapture(expr, cursor, '(')) - st) > 1 ?
  1357. new String(expr, st + 1, cursor - st - 1) : "";
  1358. cursor++;
  1359. Object[] preConvArgs;
  1360. Object[] args;
  1361. Class[] argTypes;
  1362. ExecutableStatement[] es;
  1363. List<char[]> subtokens;
  1364. if (tk.length() == 0) {
  1365. args = preConvArgs = ParseTools.EMPTY_OBJ_ARR;
  1366. argTypes = ParseTools.EMPTY_CLS_ARR;
  1367. es = null;
  1368. subtokens = null;
  1369. }
  1370. else {
  1371. subtokens = parseParameterList(tk.toCharArray(), 0, -1);
  1372. es = new ExecutableStatement[subtokens.size()];
  1373. args = new Object[subtokens.size()];
  1374. argTypes = new Class[subtokens.size()];
  1375. preConvArgs = new Object[es.length];
  1376. for (int i = 0; i < subtokens.size(); i++) {
  1377. assert debug("subtoken[" + i + "] { " + new String(subtokens.get(i)) + " }");
  1378. preConvArgs[i] = args[i] = (es[i] = (ExecutableStatement) subCompileExpression(subtokens.get(i), pCtx))
  1379. .getValue(this.thisRef, this.thisRef, variableFactory);
  1380. if (es[i].isExplicitCast()) argTypes[i] = es[i].getKnownEgressType();
  1381. }
  1382. if (pCtx.isStrictTypeEnforcement()) {
  1383. for (int i = 0; i < args.length; i++) {
  1384. argTypes[i] = es[i].getKnownEgressType();
  1385. }
  1386. }
  1387. else {
  1388. for (int i = 0; i < args.length; i++) {
  1389. if (argTypes[i] != null) continue;
  1390. if (es[i].getKnownEgressType() == Object.class) {
  1391. argTypes[i] = args[i] == null ? null : args[i].getClass();
  1392. }
  1393. else {
  1394. argTypes[i] = es[i].getKnownEgressType();
  1395. }
  1396. }
  1397. }
  1398. }
  1399. if (first && variableFactory != null && variableFactory.isResolveable(name)) {
  1400. Object ptr = variableFactory.getVariableResolver(name).getValue();
  1401. if (ptr instanceof Method) {
  1402. ctx = ((Method) ptr).getDeclaringClass();
  1403. name = ((Method) ptr).getName();
  1404. }
  1405. else if (ptr instanceof MethodStub) {
  1406. ctx = ((MethodStub) ptr).getClassReference();
  1407. name = ((MethodStub) ptr).getMethodName();
  1408. }
  1409. else if (ptr instanceof Function) {
  1410. if (es != null && es.length != 0) {
  1411. compiledInputs.addAll(Arrays.asList(es));
  1412. intPush(es.length);
  1413. assert debug("ANEWARRAY [" + es.length + "]");
  1414. mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
  1415. assert debug("ASTORE 4");
  1416. mv.visitVarInsn(ASTORE, 4);
  1417. for (int i = 0; i < es.length; i++) {
  1418. assert debug("ALOAD 4");
  1419. mv.visitVarInsn(ALOAD, 4);
  1420. intPush(i);
  1421. loadField(i);
  1422. assert debug("ALOAD 1");
  1423. mv.visitVarInsn(ALOAD, 1);
  1424. assert debug("ALOAD 3");
  1425. mv.visitIntInsn(ALOAD, 3);
  1426. assert debug("INVOKEINTERFACE ExecutableStatement.getValue");
  1427. mv.visitMethodInsn(INVOKEINTERFACE, NAMESPACE + "compiler/ExecutableStatement", "getValue",
  1428. "(Ljava/lang/Object;L" + NAMESPACE + "integration/VariableResolverFactory;)Ljava/lang/Object;");
  1429. assert debug("AASTORE");
  1430. mv.visitInsn(AASTORE);
  1431. }
  1432. }
  1433. else {
  1434. assert debug("ACONST_NULL");
  1435. mv.visitInsn(ACONST_NULL);
  1436. assert debug("CHECKCAST java/lang/Object");
  1437. mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
  1438. assert debug("ASTORE 4");
  1439. mv.visitVarInsn(ASTORE, 4);
  1440. }
  1441. if (variableFactory.isIndexedFactory() && variableFactory.isTarget(name)) {
  1442. loadVariableByIndex(variableFactory.variableIndexOf(name));
  1443. }
  1444. else {
  1445. loadVariableByName(name);
  1446. }
  1447. checkcast(Function.class);
  1448. assert debug("ALOAD 1");
  1449. mv.visitVarInsn(ALOAD, 1);
  1450. assert debug("ALOAD 2");
  1451. mv.visitVarInsn(ALOAD, 2);
  1452. assert debug("ALOAD 3");
  1453. mv.visitVarInsn(ALOAD, 3);
  1454. assert debug("ALOAD 4");
  1455. mv.visitVarInsn(ALOAD, 4);
  1456. assert debug("INVOKEVIRTUAL Function.call");
  1457. mv.visitMethodInsn(INVOKEVIRTUAL,
  1458. getInternalName(Function.class),
  1459. "call",
  1460. "(Ljava/lang/Object;Ljava/lang/Object;L" + NAMESPACE
  1461. + "integration/VariableResolverFactory;[Ljava/lang/Object;)Ljava/lang/Object;");
  1462. return ((Function) ptr).call(ctx, thisRef, variableFactory, args);
  1463. }
  1464. else {
  1465. throw new OptimizationFailure("attempt to optimize a method call for a reference that does not point to a method: "
  1466. + name + " (reference is type: " + (ctx != null ? ctx.getClass().getName() : null) + ")");
  1467. }
  1468. first = false;
  1469. }
  1470. else if (returnType != null && returnType.isPrimitive()) {
  1471. //noinspection unchecked
  1472. wrapPrimitive(returnType);
  1473. }
  1474. /**
  1475. * If the target object is an instance of java.lang.Class itself then do not
  1476. * adjust the Class scope target.
  1477. */
  1478. boolean classTarget = false;
  1479. Class<?> cls = currType != null ? currType : ((classTarget = ctx instanceof Class) ? (Class<?>) ctx : ctx.getClass());
  1480. currType = null;
  1481. Method m;
  1482. Class[] parameterTypes = null;
  1483. /**
  1484. * Try to find an instance method from the class target.
  1485. */
  1486. if ((m = getBestCandidate(argTypes, name, cls, cls.getMethods(), false, classTarget)) != null) {
  1487. parameterTypes = m.getParameterTypes();
  1488. }
  1489. if (m == null && classTarget) {
  1490. /**
  1491. * If we didn't find anything, maybe we're looking for the actual java.lang.Class methods.
  1492. */
  1493. if ((m = getBestCandidate(argTypes, name, cls, Class.class.getMethods(), false)) != null) {
  1494. parameterTypes = m.getParameterTypes();
  1495. }
  1496. }
  1497. // If we didn't find anything and the declared class is different from the actual one try also with the actual one
  1498. if (m == null && cls != ctx.getClass() && !(ctx instanceof Class)) {
  1499. cls = ctx.getClass();
  1500. if ((m = getBestCandidate(argTypes, name, cls, cls.getMethods(), false, classTarget)) != null) {
  1501. parameterTypes = m.getParameterTypes();
  1502. }
  1503. }
  1504. if (es != null && m != null && m.isVarArgs() && (es.length != parameterTypes.length || !(es[es.length-1] instanceof ExecutableAccessor))) {
  1505. // normalize ExecutableStatement for varargs
  1506. ExecutableStatement[] varArgEs = new ExecutableStatement[parameterTypes.length];
  1507. int varArgStart = parameterTypes.length-1;
  1508. for (int i = 0; i < varArgStart; i++) varArgEs[i] = es[i];
  1509. String varargsTypeName = parameterTypes[parameterTypes.length-1].getComponentType().getName();
  1510. StringBuilder sb = new StringBuilder("new ").append(varargsTypeName).append("[] {");
  1511. for (int i = varArgStart; i < subtokens.size(); i++) {
  1512. sb.append(subtokens.get(i));
  1513. if (i < subtokens.size()-1) sb.append(",");
  1514. }
  1515. String varArgExpr = sb.append("}").toString();
  1516. char[] token = varArgExpr.toCharArray();
  1517. varArgEs[varArgStart] = ((ExecutableStatement)subCompileExpression(token, pCtx));
  1518. es = varArgEs;
  1519. if (preConvArgs.length == parameterTypes.length-1) {
  1520. // empty vararg
  1521. Object[] preConvArgsForVarArg = new Object[parameterTypes.length];
  1522. for (int i = 0; i < preConvArgs.length; i++) preConvArgsForVarArg[i] = preConvArgs[i];
  1523. preConvArgsForVarArg[parameterTypes.length-1] = Array.newInstance(parameterTypes[parameterTypes.length-1].getComponentType(), 0);
  1524. preConvArgs = preConvArgsForVarArg;
  1525. }
  1526. }
  1527. int inputsOffset = compiledInputs.size();
  1528. if (es != null) {
  1529. for (ExecutableStatement e : es) {
  1530. if (e instanceof ExecutableLiteral) {
  1531. continue;
  1532. }
  1533. compiledInputs.add(e);
  1534. }
  1535. }
  1536. if (first) {
  1537. assert debug("ALOAD 1 (D) ");
  1538. mv.visitVarInsn(ALOAD, 1);
  1539. }
  1540. if (m == null) {
  1541. StringAppender errorBuild = new StringAppender();
  1542. if (parameterTypes != null) {
  1543. for (int i = 0; i < args.length; i++) {
  1544. errorBuild.append(parameterTypes[i] != null ? parameterTypes[i].getClass().getName() : null);
  1545. if (i < args.length - 1) errorBuild.append(", ");
  1546. }
  1547. }
  1548. if ("size".equals(name) && args.length == 0 && cls.isArray()) {
  1549. anyArrayCheck(cls);
  1550. assert debug("ARRAYLENGTH");
  1551. mv.visitInsn(ARRAYLENGTH);
  1552. wrapPrimitive(int.class);
  1553. return getLength(ctx);
  1554. }
  1555. throw new CompileException("unable to resolve method: " + cls.getName() + "."
  1556. + name + "(" + errorBuild.toString() + ") [arglength=" + args.length + "]", expr, st);
  1557. }
  1558. else {
  1559. m = getWidenedTarget(m);
  1560. if (es != null) {
  1561. ExecutableStatement cExpr;
  1562. for (int i = 0; i < es.length; i++) {
  1563. if ((cExpr = es[i]).getKnownIngressType() == null) {
  1564. cExpr.setKnownIngressType(parameterTypes[i]);
  1565. cExpr.computeTypeConversionRule();
  1566. }
  1567. if (!cExpr.isConvertableIngressEgress() && i < args.length) {
  1568. args[i] = convert(args[i], paramTypeVarArgsSafe(parameterTypes, i, m.isVarArgs()));
  1569. }
  1570. }
  1571. }
  1572. else {
  1573. /**
  1574. * Coerce any types if required.
  1575. */
  1576. for (int i = 0; i < args.length; i++) {
  1577. args[i] = convert(args[i], paramTypeVarArgsSafe(parameterTypes, i, m.isVarArgs()));
  1578. }
  1579. }
  1580. if (m.getParameterTypes().length == 0) {
  1581. if ((m.getModifiers() & STATIC) != 0) {
  1582. assert debug("INVOKESTATIC " + m.getName());
  1583. mv.visitMethodInsn(INVOKESTATIC, getInternalName(m.getDeclaringClass()), m.getName(), getMethodDescriptor(m));
  1584. }
  1585. else {
  1586. assert debug("CHECKCAST " + getInternalName(m.getDeclaringClass()));
  1587. mv.visitTypeInsn(CHECKCAST, getInternalName(m.getDeclaringClass()));
  1588. if (m.getDeclaringClass().isInterface()) {
  1589. assert debug("INVOKEINTERFACE " + m.getName());
  1590. mv.visitMethodInsn(INVOKEINTERFACE, getInternalName(m.getDeclaringClass()), m.getName(),
  1591. getMethodDescriptor(m));
  1592. }
  1593. else {
  1594. assert debug("INVOKEVIRTUAL " + m.getName());
  1595. mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(m.getDeclaringClass()), m.getName(),
  1596. getMethodDescriptor(m));
  1597. }
  1598. }
  1599. returnType = m.getReturnType();
  1600. stacksize++;
  1601. }
  1602. else {
  1603. if ((m.getModifiers() & STATIC) == 0) {
  1604. assert debug("CHECKCAST " + getInternalName(cls));
  1605. mv.visitTypeInsn(CHECKCAST, getInternalName(cls));
  1606. }
  1607. for (int i = 0; i < es.length; i++) {
  1608. if (es[i] instanceof ExecutableLiteral) {
  1609. ExecutableLiteral literal = (ExecutableLiteral) es[i];
  1610. if (literal.getLiteral() == null) {
  1611. assert debug("ICONST_NULL");
  1612. mv.visitInsn(ACONST_NULL);
  1613. continue;
  1614. }
  1615. else if (parameterTypes[i] == int.class && literal.intOptimized()) {
  1616. intPush(literal.getInteger32());
  1617. continue;
  1618. }
  1619. else if (parameterTypes[i] == int.class && preConvArgs[i] instanceof Integer) {
  1620. intPush((Integer) preConvArgs[i]);
  1621. continue;
  1622. }
  1623. else if (parameterTypes[i] == boolean.class) {
  1624. boolean bool = DataConversion.convert(literal.getLiteral(), Boolean.class);
  1625. assert debug(bool ? "ICONST_1" : "ICONST_0");
  1626. mv.visitInsn(bool ? ICONST_1 : ICONST_0);
  1627. continue;
  1628. }
  1629. else {
  1630. Object lit = literal.getLiteral();
  1631. if (parameterTypes[i] == Object.class) {
  1632. if (isPrimitiveWrapper(lit.getClass())) {
  1633. if (lit.getClass() == Integer.class) {
  1634. intPush((Integer) lit);
  1635. }
  1636. else {
  1637. assert debug("LDC " + lit);
  1638. mv.visitLdcInsn(lit);
  1639. }
  1640. wrapPrimitive(lit.getClass());
  1641. }
  1642. else if (lit instanceof String) {
  1643. mv.visitLdcInsn(lit);
  1644. checkcast(Object.class);
  1645. }
  1646. continue;
  1647. }
  1648. else if (canConvert(parameterTypes[i], lit.getClass())) {
  1649. Object c = convert(lit, parameterTypes[i]);
  1650. if (c instanceof Class) {
  1651. ldcClassConstant((Class) c);
  1652. }
  1653. else {
  1654. assert debug("LDC " + lit + " (" + lit.getClass().getName() + ")");
  1655. mv.visitLdcInsn(convert(lit, parameterTypes[i]));
  1656. if (isPrimitiveWrapper(parameterTypes[i])) {
  1657. wrapPrimitive(lit.getClass());
  1658. }
  1659. }
  1660. continue;
  1661. }
  1662. else {
  1663. throw new OptimizationNotSupported();
  1664. }
  1665. }
  1666. }
  1667. assert debug("ALOAD 0");
  1668. mv.visitVarInsn(ALOAD, 0);
  1669. assert debug("GETFIELD p" + inputsOffset);
  1670. mv.visitFieldInsn(GETFIELD, className, "p" + inputsOffset, "L" + NAMESPACE + "compiler/ExecutableStatement;");
  1671. inputsOffset++;
  1672. assert debug("ALOAD 2");
  1673. mv.visitVarInsn(ALOAD, 2);
  1674. assert debug("ALOAD 3");
  1675. mv.visitVarInsn(ALOAD, 3);
  1676. assert debug("INVOKEINTERFACE ExecutableStatement.getValue");
  1677. mv.visitMethodInsn(INVOKEINTERFACE, getInternalName(ExecutableStatement.class), "getValue",
  1678. "(Ljava/lang/Object;L" + NAMESPACE + "integration/VariableResolverFactory;)Ljava/lang/Object;");
  1679. if (parameterTypes[i].isPrimitive()) {
  1680. if (preConvArgs[i] == null ||
  1681. (parameterTypes[i] != String.class &&
  1682. !parameterTypes[i].isAssignableFrom(preConvArgs[i].getClass()))) {
  1683. ldcClassConstant(getWrapperClass(parameterTypes[i]));
  1684. assert debug("INVOKESTATIC DataConversion.convert");
  1685. mv.visitMethodInsn(INVOKESTATIC, NAMESPACE + "DataConversion", "convert",
  1686. "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
  1687. }
  1688. unwrapPrimitive(parameterTypes[i]);
  1689. }
  1690. else if (preConvArgs[i] == null ||
  1691. (parameterTypes[i] != String.class &&
  1692. !parameterTypes[i].isAssignableFrom(preConvArgs[i].getClass()))) {
  1693. ldcClassConstant(parameterTypes[i]);
  1694. assert debug("INVOKESTATIC DataConversion.convert");
  1695. mv.visitMethodInsn(INVOKESTATIC, NAMESPACE + "DataConversion", "convert",
  1696. "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
  1697. assert debug("CHECKCAST " + getInternalName(parameterTypes[i]));
  1698. mv.visitTypeInsn(CHECKCAST, getInternalName(parameterTypes[i]));
  1699. }
  1700. else if (parameterTypes[i] == String.class) {
  1701. assert debug("<<<DYNAMIC TYPE OPTIMIZATION STRING>>");
  1702. mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf",
  1703. "(Ljava/lang/Object;)Ljava/lang/String;");
  1704. }
  1705. else {
  1706. assert debug("<<<DYNAMIC TYPING BYPASS>>>");
  1707. assert debug("<<<OPT. JUSTIFICATION " + parameterTypes[i] + "=" + preConvArgs[i].getClass() + ">>>");
  1708. assert debug("CHECKCAST " + getInternalName(parameterTypes[i]));
  1709. mv.visitTypeInsn(CHECKCAST, getInternalName(parameterTypes[i]));
  1710. }
  1711. }
  1712. if ((m.getModifiers() & STATIC) != 0) {
  1713. assert debug("INVOKESTATIC: " + m.getName());
  1714. mv.visitMethodInsn(INVOKESTATIC, getInternalName(m.getDeclaringClass()), m.getName(), getMethodDescriptor(m));
  1715. }
  1716. else {
  1717. if (m.getDeclaringClass().isInterface() && (m.getDeclaringClass() != cls
  1718. || (ctx != null && ctx.getClass() != m.getDeclaringClass()))) {
  1719. assert debug("INVOKEINTERFACE: " + getInternalName(m.getDeclaringClass()) + "." + m.getName());
  1720. mv.visitMethodInsn(INVOKEINTERFACE, getInternalName(m.getDeclaringClass()), m.getName(),
  1721. getMethodDescriptor(m));
  1722. }
  1723. else {
  1724. assert debug("INVOKEVIRTUAL: " + getInternalName(cls) + "." + m.getName());
  1725. mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(cls), m.getName(),
  1726. getMethodDescriptor(m));
  1727. }
  1728. }
  1729. returnType = m.getReturnType();
  1730. stacksize++;
  1731. }
  1732. Object o = m.invoke(ctx, normalizeArgsForVarArgs(parameterTypes, args, m.isVarArgs()));
  1733. if (hasNullMethodHandler()) {
  1734. writeOutNullHandler(m, 1);
  1735. if (o == null) o = getNullMethodHandler().getProperty(m.getName(), ctx, variableFactory);
  1736. }
  1737. currType = toNonPrimitiveType(m.getReturnType());
  1738. return o;
  1739. }
  1740. }
  1741. private void dataConversion(Class target) {
  1742. if (target.equals(Object.class)) return;
  1743. ldcClassConstant(target);
  1744. assert debug("INVOKESTATIC " + NAMESPACE + "DataConversion.convert");
  1745. mv.visitMethodInsn(INVOKESTATIC, NAMESPACE + "DataConversion", "convert",
  1746. "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
  1747. }
  1748. private static MVELClassLoader classLoader;
  1749. public static void setMVELClassLoader(MVELClassLoader cl) {
  1750. classLoader = cl;
  1751. }
  1752. public static MVELClassLoader getMVELClassLoader() {
  1753. return classLoader;
  1754. }
  1755. public void init() {
  1756. try {
  1757. classLoader = new JITClassLoader(currentThread().getContextClassLoader());
  1758. }
  1759. catch (Exception e) {
  1760. throw new RuntimeException(e);
  1761. }
  1762. }
  1763. private ContextClassLoader getContextClassLoader() {
  1764. return pCtx == null ? null : new ContextClassLoader(pCtx.getClassLoader());
  1765. }
  1766. private static class ContextClassLoader extends ClassLoader {
  1767. ContextClassLoader(ClassLoader classLoader) {
  1768. super(classLoader);
  1769. }
  1770. Class<?> defineClass(String name, byte[] b) {
  1771. return defineClass(name, b, 0, b.length);
  1772. }
  1773. }
  1774. private java.lang.Class loadClass(String className, byte[] b) throws Exception {
  1775. /**
  1776. * This must be synchronized. Two classes cannot be simultaneously deployed in the JVM.
  1777. */
  1778. ContextClassLoader contextClassLoader = getContextClassLoader();
  1779. return contextClassLoader == null ?
  1780. classLoader.defineClassX(className, b, 0, b.length) :
  1781. contextClassLoader.defineClass(className, b);
  1782. }
  1783. private boolean debug(String instruction) {
  1784. if (buildLog != null) {
  1785. buildLog.append(instruction).append("\n");
  1786. }
  1787. return true;
  1788. }
  1789. @SuppressWarnings({"SameReturnValue"})
  1790. public String getName() {
  1791. return "ASM";
  1792. }
  1793. public Object getResultOptPass() {
  1794. return val;
  1795. }
  1796. private Class getWrapperClass(Class cls) {
  1797. if (cls == boolean.class) {
  1798. return Boolean.class;
  1799. }
  1800. else if (cls == int.class) {
  1801. return Integer.class;
  1802. }
  1803. else if (cls == float.class) {
  1804. return Float.class;
  1805. }
  1806. else if (cls == double.class) {
  1807. return Double.class;
  1808. }
  1809. else if (cls == short.class) {
  1810. return Short.class;
  1811. }
  1812. else if (cls == long.class) {
  1813. return Long.class;
  1814. }
  1815. else if (cls == byte.class) {
  1816. return Byte.class;
  1817. }
  1818. else if (cls == char.class) {
  1819. return Character.class;
  1820. }
  1821. return cls;
  1822. }
  1823. private void unwrapPrimitive(Class cls) {
  1824. if (cls == boolean.class) {
  1825. assert debug("CHECKCAST java/lang/Boolean");
  1826. mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
  1827. assert debug("INVOKEVIRTUAL java/lang/Boolean.booleanValue");
  1828. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
  1829. }
  1830. else if (cls == int.class) {
  1831. assert debug("CHECKCAST java/lang/Integer");
  1832. mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
  1833. assert debug("INVOKEVIRTUAL java/lang/Integer.intValue");
  1834. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
  1835. }
  1836. else if (cls == float.class) {
  1837. assert debug("CHECKCAST java/lang/Float");
  1838. mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
  1839. assert debug("INVOKEVIRTUAL java/lang/Float.floatValue");
  1840. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
  1841. }
  1842. else if (cls == double.class) {
  1843. assert debug("CHECKCAST java/lang/Double");
  1844. mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
  1845. assert debug("INVOKEVIRTUAL java/lang/Double.doubleValue");
  1846. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
  1847. }
  1848. else if (cls == short.class) {
  1849. assert debug("CHECKCAST java/lang/Short");
  1850. mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
  1851. assert debug("INVOKEVIRTUAL java/lang/Short.shortValue");
  1852. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
  1853. }
  1854. else if (cls == long.class) {
  1855. assert debug("CHECKCAST java/lang/Long");
  1856. mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
  1857. assert debug("INVOKEVIRTUAL java/lang/Long.longValue");
  1858. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
  1859. }
  1860. else if (cls == byte.class) {
  1861. assert debug("CHECKCAST java/lang/Byte");
  1862. mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
  1863. assert debug("INVOKEVIRTUAL java/lang/Byte.byteValue");
  1864. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
  1865. }
  1866. else if (cls == char.class) {
  1867. assert debug("CHECKCAST java/lang/Character");
  1868. mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
  1869. assert debug("INVOKEVIRTUAL java/lang/Character.charValue");
  1870. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
  1871. }
  1872. }
  1873. private void wrapPrimitive(Class<? extends Object> cls) {
  1874. if (OPCODES_VERSION == Opcodes.V1_4) {
  1875. /**
  1876. * JAVA 1.4 SUCKS! DIE 1.4 DIE!!!
  1877. */
  1878. debug("** Using 1.4 Bytecode **");
  1879. if (cls == boolean.class || cls == Boolean.class) {
  1880. debug("NEW java/lang/Boolean");
  1881. mv.visitTypeInsn(NEW, "java/lang/Boolean");
  1882. debug("DUP X1");
  1883. mv.visitInsn(DUP_X1);
  1884. debug("SWAP");
  1885. mv.visitInsn(SWAP);
  1886. debug("INVOKESPECIAL java/lang/Boolean.<init>::(Z)V");
  1887. mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Boolean", "<init>", "(Z)V");
  1888. }
  1889. else if (cls == int.class || cls == Integer.class) {
  1890. debug("NEW java/lang/Integer");
  1891. mv.visitTypeInsn(NEW, "java/lang/Integer");
  1892. debug("DUP X1");
  1893. mv.visitInsn(DUP_X1);
  1894. debug("SWAP");
  1895. mv.visitInsn(SWAP);
  1896. debug("INVOKESPECIAL java/lang/Integer.<init>::(I)V");
  1897. mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer", "<init>", "(I)V");
  1898. }
  1899. else if (cls == float.class || cls == Float.class) {
  1900. debug("NEW java/lang/Float");
  1901. mv.visitTypeInsn(NEW, "java/lang/Float");
  1902. debug("DUP X1");
  1903. mv.visitInsn(DUP_X1);
  1904. debug("SWAP");
  1905. mv.visitInsn(SWAP);
  1906. debug("INVOKESPECIAL java/lang/Float.<init>::(F)V");
  1907. mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Float", "<init>", "(F)V");
  1908. }
  1909. else if (cls == double.class || cls == Double.class) {
  1910. debug("NEW java/lang/Double");
  1911. mv.visitTypeInsn(NEW, "java/lang/Double");
  1912. debug("DUP X2");
  1913. mv.visitInsn(DUP_X2);
  1914. debug("DUP X2");
  1915. mv.visitInsn(DUP_X2);
  1916. debug("POP");
  1917. mv.visitInsn(POP);
  1918. debug("INVOKESPECIAL java/lang/Double.<init>::(D)V");
  1919. mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Double", "<init>", "(D)V");
  1920. }
  1921. else if (cls == short.class || cls == Short.class) {
  1922. debug("NEW java/lang/Short");
  1923. mv.visitTypeInsn(NEW, "java/lang/Short");
  1924. debug("DUP X1");
  1925. mv.visitInsn(DUP_X1);
  1926. debug("SWAP");
  1927. mv.visitInsn(SWAP);
  1928. debug("INVOKESPECIAL java/lang/Short.<init>::(S)V");
  1929. mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Short", "<init>", "(S)V");
  1930. }
  1931. else if (cls == long.class || cls == Long.class) {
  1932. debug("NEW java/lang/Long");
  1933. mv.visitTypeInsn(NEW, "java/lang/Long");
  1934. debug("DUP X1");
  1935. mv.visitInsn(DUP_X1);
  1936. debug("SWAP");
  1937. mv.visitInsn(SWAP);
  1938. debug("INVOKESPECIAL java/lang/Long.<init>::(L)V");
  1939. mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Float", "<init>", "(L)V");
  1940. }
  1941. else if (cls == byte.class || cls == Byte.class) {
  1942. debug("NEW java/lang/Byte");
  1943. mv.visitTypeInsn(NEW, "java/lang/Byte");
  1944. debug("DUP X1");
  1945. mv.visitInsn(DUP_X1);
  1946. debug("SWAP");
  1947. mv.visitInsn(SWAP);
  1948. debug("INVOKESPECIAL java/lang/Byte.<init>::(B)V");
  1949. mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Byte", "<init>", "(B)V");
  1950. }
  1951. else if (cls == char.class || cls == Character.class) {
  1952. debug("NEW java/lang/Character");
  1953. mv.visitTypeInsn(NEW, "java/lang/Character");
  1954. debug("DUP X1");
  1955. mv.visitInsn(DUP_X1);
  1956. debug("SWAP");
  1957. mv.visitInsn(SWAP);
  1958. debug("INVOKESPECIAL java/lang/Character.<init>::(C)V");
  1959. mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Character", "<init>", "(C)V");
  1960. }
  1961. }
  1962. else {
  1963. if (cls == boolean.class || cls == Boolean.class) {
  1964. debug("INVOKESTATIC java/lang/Boolean.valueOf");
  1965. mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
  1966. }
  1967. else if (cls == int.class || cls == Integer.class) {
  1968. debug("INVOKESTATIC java/lang/Integer.valueOf");
  1969. mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
  1970. }
  1971. else if (cls == float.class || cls == Float.class) {
  1972. debug("INVOKESTATIC java/lang/Float.valueOf");
  1973. mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
  1974. }
  1975. else if (cls == double.class || cls == Double.class) {
  1976. debug("INVOKESTATIC java/lang/Double.valueOf");
  1977. mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
  1978. }
  1979. else if (cls == short.class || cls == Short.class) {
  1980. debug("INVOKESTATIC java/lang/Short.valueOf");
  1981. mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
  1982. }
  1983. else if (cls == long.class || cls == Long.class) {
  1984. debug("INVOKESTATIC java/lang/Long.valueOf");
  1985. mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
  1986. }
  1987. else if (cls == byte.class || cls == Byte.class) {
  1988. debug("INVOKESTATIC java/lang/Byte.valueOf");
  1989. mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
  1990. }
  1991. else if (cls == char.class || cls == Character.class) {
  1992. debug("INVOKESTATIC java/lang/Character.valueOf");
  1993. mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
  1994. }
  1995. }
  1996. }
  1997. private void anyArrayCheck(Class cls) {
  1998. if (cls == boolean[].class) {
  1999. assert debug("CHECKCAST [Z");
  2000. mv.visitTypeInsn(CHECKCAST, "[Z");
  2001. }
  2002. else if (cls == int[].class) {
  2003. assert debug("CHECKCAST [I");
  2004. mv.visitTypeInsn(CHECKCAST, "[I");
  2005. }
  2006. else if (cls == float[].class) {
  2007. assert debug("CHECKCAST [F");
  2008. mv.visitTypeInsn(CHECKCAST, "[F");
  2009. }
  2010. else if (cls == double[].class) {
  2011. assert debug("CHECKCAST [D");
  2012. mv.visitTypeInsn(CHECKCAST, "[D");
  2013. }
  2014. else if (cls == short[].class) {
  2015. assert debug("CHECKCAST [S");
  2016. mv.visitTypeInsn(CHECKCAST, "[S");
  2017. }
  2018. else if (cls == long[].class) {
  2019. assert debug("CHECKCAST [J");
  2020. mv.visitTypeInsn(CHECKCAST, "[J");
  2021. }
  2022. else if (cls == byte[].class) {
  2023. assert debug("CHECKCAST [B");
  2024. mv.visitTypeInsn(CHECKCAST, "[B");
  2025. }
  2026. else if (cls == char[].class) {
  2027. assert debug("CHECKCAST [C");
  2028. mv.visitTypeInsn(CHECKCAST, "[C");
  2029. }
  2030. else {
  2031. assert debug("CHECKCAST [Ljava/lang/Object;");
  2032. mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
  2033. }
  2034. }
  2035. private void writeOutLiteralWrapped(Object lit) {
  2036. if (lit instanceof Integer) {
  2037. intPush((Integer) lit);
  2038. wrapPrimitive(int.class);
  2039. return;
  2040. }
  2041. assert debug("LDC " + lit);
  2042. if (lit instanceof String) {
  2043. mv.visitLdcInsn(lit);
  2044. }
  2045. else if (lit instanceof Long) {
  2046. mv.visitLdcInsn(lit);
  2047. wrapPrimitive(long.class);
  2048. }
  2049. else if (lit instanceof Float) {
  2050. mv.visitLdcInsn(lit);
  2051. wrapPrimitive(float.class);
  2052. }
  2053. else if (lit instanceof Double) {
  2054. mv.visitLdcInsn(lit);
  2055. wrapPrimitive(double.class);
  2056. }
  2057. else if (lit instanceof Short) {
  2058. mv.visitLdcInsn(lit);
  2059. wrapPrimitive(short.class);
  2060. }
  2061. else if (lit instanceof Character) {
  2062. mv.visitLdcInsn(lit);
  2063. wrapPrimitive(char.class);
  2064. }
  2065. else if (lit instanceof Boolean) {
  2066. mv.visitLdcInsn(lit);
  2067. wrapPrimitive(boolean.class);
  2068. }
  2069. else if (lit instanceof Byte) {
  2070. mv.visitLdcInsn(lit);
  2071. wrapPrimitive(byte.class);
  2072. }
  2073. }
  2074. public void arrayStore(Class cls) {
  2075. if (cls.isPrimitive()) {
  2076. if (cls == int.class) {
  2077. assert debug("IASTORE");
  2078. mv.visitInsn(IASTORE);
  2079. }
  2080. else if (cls == char.class) {
  2081. assert debug("CASTORE");
  2082. mv.visitInsn(CASTORE);
  2083. }
  2084. else if (cls == boolean.class) {
  2085. assert debug("BASTORE");
  2086. mv.visitInsn(BASTORE);
  2087. }
  2088. else if (cls == double.class) {
  2089. assert debug("DASTORE");
  2090. mv.visitInsn(DASTORE);
  2091. }
  2092. else if (cls == float.class) {
  2093. assert debug("FASTORE");
  2094. mv.visitInsn(FASTORE);
  2095. }
  2096. else if (cls == short.class) {
  2097. assert debug("SASTORE");
  2098. mv.visitInsn(SASTORE);
  2099. }
  2100. else if (cls == long.class) {
  2101. assert debug("LASTORE");
  2102. mv.visitInsn(LASTORE);
  2103. }
  2104. else if (cls == byte.class) {
  2105. assert debug("BASTORE");
  2106. mv.visitInsn(BASTORE);
  2107. }
  2108. }
  2109. else {
  2110. assert debug("AASTORE");
  2111. mv.visitInsn(AASTORE);
  2112. }
  2113. }
  2114. public void wrapRuntimeConverstion(Class toType) {
  2115. ldcClassConstant(getWrapperClass(toType));
  2116. assert debug("INVOKESTATIC DataConversion.convert");
  2117. mv.visitMethodInsn(INVOKESTATIC, "" + NAMESPACE + "DataConversion", "convert",
  2118. "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
  2119. }
  2120. private Object addSubstatement(ExecutableStatement stmt) {
  2121. if (stmt instanceof ExecutableAccessor) {
  2122. ExecutableAccessor ea = (ExecutableAccessor) stmt;
  2123. if (ea.getNode().isIdentifier() && !ea.getNode().isDeepProperty()) {
  2124. loadVariableByName(ea.getNode().getName());
  2125. return null;
  2126. }
  2127. }
  2128. compiledInputs.add(stmt);
  2129. assert debug("ALOAD 0");
  2130. mv.visitVarInsn(ALOAD, 0);
  2131. assert debug("GETFIELD p" + (compiledInputs.size() - 1));
  2132. mv.visitFieldInsn(GETFIELD, className, "p" + (compiledInputs.size() - 1),
  2133. "L" + NAMESPACE + "compiler/ExecutableStatement;");
  2134. assert debug("ALOAD 2");
  2135. mv.visitVarInsn(ALOAD, 2);
  2136. assert debug("ALOAD 3");
  2137. mv.visitVarInsn(ALOAD, 3);
  2138. assert debug("INVOKEINTERFACE ExecutableStatement.getValue");
  2139. mv.visitMethodInsn(INVOKEINTERFACE, getInternalName(ExecutableStatement.class), "getValue",
  2140. "(Ljava/lang/Object;L" + NAMESPACE + "integration/VariableResolverFactory;)Ljava/lang/Object;");
  2141. return null;
  2142. }
  2143. private void loadVariableByName(String name) {
  2144. assert debug("ALOAD 3");
  2145. mv.visitVarInsn(ALOAD, 3);
  2146. assert debug("LDC \"" + name + "\"");
  2147. mv.visitLdcInsn(name);
  2148. assert debug("INVOKEINTERFACE " + NAMESPACE + "integration/VariableResolverFactory.getVariableResolver");
  2149. mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE + "integration/VariableResolverFactory",
  2150. "getVariableResolver", "(Ljava/lang/String;)L" + NAMESPACE + "integration/VariableResolver;");
  2151. assert debug("INVOKEINTERFACE " + NAMESPACE + "integration/VariableResolver.getValue");
  2152. mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE + "integration/VariableResolver",
  2153. "getValue", "()Ljava/lang/Object;");
  2154. returnType = Object.class;
  2155. }
  2156. private void loadVariableByIndex(int pos) {
  2157. assert debug("ALOAD 3");
  2158. mv.visitVarInsn(ALOAD, 3);
  2159. assert debug("PUSH IDX VAL =" + pos);
  2160. intPush(pos);
  2161. assert debug("INVOKEINTERFACE " + NAMESPACE + "integration/VariableResolverFactory.getIndexedVariableResolver");
  2162. mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE + "integration/VariableResolverFactory",
  2163. "getIndexedVariableResolver", "(I)L" + NAMESPACE + "integration/VariableResolver;");
  2164. assert debug("INVOKEINTERFACE " + NAMESPACE + "integration/VariableResolver.getValue");
  2165. mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE + "integration/VariableResolver",
  2166. "getValue", "()Ljava/lang/Object;");
  2167. returnType = Object.class;
  2168. }
  2169. private void loadField(int number) {
  2170. assert debug("ALOAD 0");
  2171. mv.visitVarInsn(ALOAD, 0);
  2172. assert debug("GETFIELD p" + number);
  2173. mv.visitFieldInsn(GETFIELD, className, "p" + number, "L" + NAMESPACE + "compiler/ExecutableStatement;");
  2174. }
  2175. private void ldcClassConstant(Class cls) {
  2176. if (OPCODES_VERSION == Opcodes.V1_4) {
  2177. assert debug("LDC \"" + cls.getName() + "\"");
  2178. mv.visitLdcInsn(cls.getName());
  2179. mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
  2180. Label l4 = new Label();
  2181. mv.visitJumpInsn(GOTO, l4);
  2182. mv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
  2183. mv.visitInsn(DUP_X1);
  2184. mv.visitInsn(SWAP);
  2185. mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "getMessage", "()Ljava/lang/String;");
  2186. mv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V");
  2187. mv.visitInsn(ATHROW);
  2188. mv.visitLabel(l4);
  2189. }
  2190. else {
  2191. assert debug("LDC " + getType(cls));
  2192. mv.visitLdcInsn(getType(cls));
  2193. }
  2194. }
  2195. private void buildInputs() {
  2196. if (compiledInputs.size() == 0) return;
  2197. assert debug("\n{SETTING UP MEMBERS...}\n");
  2198. StringAppender constSig = new StringAppender("(");
  2199. int size = compiledInputs.size();
  2200. for (int i = 0; i < size; i++) {
  2201. assert debug("ACC_PRIVATE p" + i);
  2202. cw.visitField(ACC_PRIVATE, "p" + i, "L" + NAMESPACE + "compiler/ExecutableStatement;", null, null).visitEnd();
  2203. constSig.append("L" + NAMESPACE + "compiler/ExecutableStatement;");
  2204. }
  2205. constSig.append(")V");
  2206. assert debug("\n{CREATING INJECTION CONSTRUCTOR}\n");
  2207. MethodVisitor cv = cw.visitMethod(ACC_PUBLIC, "<init>", constSig.toString(), null, null);
  2208. cv.visitCode();
  2209. assert debug("ALOAD 0");
  2210. cv.visitVarInsn(ALOAD, 0);
  2211. assert debug("INVOKESPECIAL java/lang/Object.<init>");
  2212. cv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
  2213. for (int i = 0; i < size; i++) {
  2214. assert debug("ALOAD 0");
  2215. cv.visitVarInsn(ALOAD, 0);
  2216. assert debug("ALOAD " + (i + 1));
  2217. cv.visitVarInsn(ALOAD, i + 1);
  2218. assert debug("PUTFIELD p" + i);
  2219. cv.visitFieldInsn(PUTFIELD, className, "p" + i, "L" + NAMESPACE + "compiler/ExecutableStatement;");
  2220. }
  2221. assert debug("RETURN");
  2222. cv.visitInsn(RETURN);
  2223. cv.visitMaxs(0, 0);
  2224. cv.visitEnd();
  2225. assert debug("}");
  2226. }
  2227. private static final int ARRAY = 0;
  2228. private static final int LIST = 1;
  2229. private static final int MAP = 2;
  2230. private static final int VAL = 3;
  2231. private int _getAccessor(Object o, Class type) {
  2232. if (o instanceof List) {
  2233. assert debug("NEW " + LIST_IMPL);
  2234. mv.visitTypeInsn(NEW, LIST_IMPL);
  2235. assert debug("DUP");
  2236. mv.visitInsn(DUP);
  2237. assert debug("DUP");
  2238. mv.visitInsn(DUP);
  2239. intPush(((List) o).size());
  2240. assert debug("INVOKESPECIAL " + LIST_IMPL + ".<init>");
  2241. mv.visitMethodInsn(INVOKESPECIAL, LIST_IMPL, "<init>", "(I)V");
  2242. for (Object item : (List) o) {
  2243. if (_getAccessor(item, type) != VAL) {
  2244. assert debug("POP");
  2245. mv.visitInsn(POP);
  2246. }
  2247. assert debug("INVOKEINTERFACE java/util/List.add");
  2248. mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z");
  2249. assert debug("POP");
  2250. mv.visitInsn(POP);
  2251. assert debug("DUP");
  2252. mv.visitInsn(DUP);
  2253. }
  2254. returnType = List.class;
  2255. return LIST;
  2256. }
  2257. else if (o instanceof Map) {
  2258. assert debug("NEW " + MAP_IMPL);
  2259. mv.visitTypeInsn(NEW, MAP_IMPL);
  2260. assert debug("DUP");
  2261. mv.visitInsn(DUP);
  2262. assert debug("DUP");
  2263. mv.visitInsn(DUP);
  2264. intPush(((Map) o).size());
  2265. assert debug("INVOKESPECIAL " + MAP_IMPL + ".<init>");
  2266. mv.visitMethodInsn(INVOKESPECIAL, MAP_IMPL, "<init>", "(I)V");
  2267. for (Object item : ((Map) o).keySet()) {
  2268. mv.visitTypeInsn(CHECKCAST, "java/util/Map");
  2269. if (_getAccessor(item, type) != VAL) {
  2270. assert debug("POP");
  2271. mv.visitInsn(POP);
  2272. }
  2273. if (_getAccessor(((Map) o).get(item), type) != VAL) {
  2274. assert debug("POP");
  2275. mv.visitInsn(POP);
  2276. }
  2277. assert debug("INVOKEINTERFACE java/util/Map.put");
  2278. mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "put",
  2279. "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
  2280. assert debug("POP");
  2281. mv.visitInsn(POP);
  2282. assert debug("DUP");
  2283. mv.visitInsn(DUP);
  2284. }
  2285. returnType = Map.class;
  2286. return MAP;
  2287. }
  2288. else if (o instanceof Object[]) {
  2289. Accessor[] a = new Accessor[((Object[]) o).length];
  2290. int i = 0;
  2291. int dim = 0;
  2292. if (type != null) {
  2293. String nm = type.getName();
  2294. while (nm.charAt(dim) == '[') dim++;
  2295. }
  2296. else {
  2297. type = Object[].class;
  2298. dim = 1;
  2299. }
  2300. try {
  2301. intPush(((Object[]) o).length);
  2302. assert debug("ANEWARRAY " + getInternalName(getSubComponentType(type)) + " (" + ((Object[]) o).length + ")");
  2303. mv.visitTypeInsn(ANEWARRAY, getInternalName(getSubComponentType(type)));
  2304. Class cls = dim > 1 ? findClass(null, repeatChar('[', dim - 1)
  2305. + "L" + getBaseComponentType(type).getName() + ";", pCtx)
  2306. : type;
  2307. assert debug("DUP");
  2308. mv.visitInsn(DUP);
  2309. for (Object item : (Object[]) o) {
  2310. intPush(i);
  2311. if (_getAccessor(item, cls) != VAL) {
  2312. assert debug("POP");
  2313. mv.visitInsn(POP);
  2314. }
  2315. assert debug("AASTORE (" + o.hashCode() + ")");
  2316. mv.visitInsn(AASTORE);
  2317. assert debug("DUP");
  2318. mv.visitInsn(DUP);
  2319. i++;
  2320. }
  2321. }
  2322. catch (ClassNotFoundException e) {
  2323. throw new RuntimeException("this error should never throw:" + getBaseComponentType(type).getName(), e);
  2324. }
  2325. return ARRAY;
  2326. }
  2327. else {
  2328. if (type.isArray()) {
  2329. writeLiteralOrSubexpression(subCompileExpression(((String) o).toCharArray(), pCtx), getSubComponentType(type));
  2330. }
  2331. else {
  2332. writeLiteralOrSubexpression(subCompileExpression(((String) o).toCharArray(), pCtx));
  2333. }
  2334. return VAL;
  2335. }
  2336. }
  2337. private Class writeLiteralOrSubexpression(Object stmt) {
  2338. return writeLiteralOrSubexpression(stmt, null, null);
  2339. }
  2340. private Class writeLiteralOrSubexpression(Object stmt, Class desiredTarget) {
  2341. return writeLiteralOrSubexpression(stmt, desiredTarget, null);
  2342. }
  2343. private Class writeLiteralOrSubexpression(Object stmt, Class desiredTarget, Class knownIngressType) {
  2344. if (stmt instanceof ExecutableLiteral) {
  2345. Class type = ((ExecutableLiteral) stmt).getLiteral().getClass();
  2346. assert debug("*** type:" + type + ";desired:" + desiredTarget);
  2347. if (type == Integer.class && desiredTarget == int.class) {
  2348. intPush(((ExecutableLiteral) stmt).getInteger32());
  2349. type = int.class;
  2350. }
  2351. else if (desiredTarget != null && desiredTarget != type) {
  2352. assert debug("*** Converting because desiredType(" + desiredTarget.getClass() + ") is not: " + type);
  2353. if (!DataConversion.canConvert(type, desiredTarget)) {
  2354. throw new CompileException("was expecting type: " + desiredTarget.getName()
  2355. + "; but found type: " + type.getName(), expr, st);
  2356. }
  2357. writeOutLiteralWrapped(convert(((ExecutableLiteral) stmt).getLiteral(), desiredTarget));
  2358. }
  2359. else {
  2360. writeOutLiteralWrapped(((ExecutableLiteral) stmt).getLiteral());
  2361. }
  2362. return type;
  2363. }
  2364. else {
  2365. literal = false;
  2366. addSubstatement((ExecutableStatement) stmt);
  2367. Class type;
  2368. if (knownIngressType == null) {
  2369. type = ((ExecutableStatement) stmt).getKnownEgressType();
  2370. }
  2371. else {
  2372. type = knownIngressType;
  2373. }
  2374. if (desiredTarget != null && type != desiredTarget) {
  2375. if (desiredTarget.isPrimitive()) {
  2376. if (type == null) throw new OptimizationFailure("cannot optimize expression: " + new String(expr) +
  2377. ": cannot determine ingress type for primitive output");
  2378. checkcast(type);
  2379. unwrapPrimitive(desiredTarget);
  2380. }
  2381. }
  2382. return type;
  2383. }
  2384. }
  2385. private void addPrintOut(String text) {
  2386. mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
  2387. mv.visitLdcInsn(text);
  2388. mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
  2389. }
  2390. public Accessor optimizeCollection(ParserContext pCtx, Object o, Class type, char[] property, int start, int offset,
  2391. Object ctx, Object thisRef, VariableResolverFactory factory) {
  2392. this.expr = property;
  2393. this.cursor = this.start = start;
  2394. this.end = start + offset;
  2395. this.length = offset;
  2396. type = toNonPrimitiveArray(type);
  2397. this.returnType = type;
  2398. this.compiledInputs = new ArrayList<ExecutableStatement>();
  2399. this.ctx = ctx;
  2400. this.thisRef = thisRef;
  2401. this.variableFactory = factory;
  2402. _initJIT();
  2403. literal = true;
  2404. _getAccessor(o, type);
  2405. _finishJIT();
  2406. try {
  2407. Accessor compiledAccessor = _initializeAccessor();
  2408. if (property != null && length > start) {
  2409. return new Union(compiledAccessor, property, start, length);
  2410. }
  2411. else {
  2412. return compiledAccessor;
  2413. }
  2414. }
  2415. catch (Exception e) {
  2416. throw new OptimizationFailure("could not optimize collection", e);
  2417. }
  2418. }
  2419. private void checkcast(Class cls) {
  2420. assert debug("CHECKCAST " + getInternalName(cls));
  2421. mv.visitTypeInsn(CHECKCAST, getInternalName(cls));
  2422. }
  2423. private void intPush(int index) {
  2424. if (index < 6) {
  2425. switch (index) {
  2426. case 0:
  2427. assert debug("ICONST_0");
  2428. mv.visitInsn(ICONST_0);
  2429. break;
  2430. case 1:
  2431. assert debug("ICONST_1");
  2432. mv.visitInsn(ICONST_1);
  2433. break;
  2434. case 2:
  2435. assert debug("ICONST_2");
  2436. mv.visitInsn(ICONST_2);
  2437. break;
  2438. case 3:
  2439. assert debug("ICONST_3");
  2440. mv.visitInsn(ICONST_3);
  2441. break;
  2442. case 4:
  2443. assert debug("ICONST_4");
  2444. mv.visitInsn(ICONST_4);
  2445. break;
  2446. case 5:
  2447. assert debug("ICONST_5");
  2448. mv.visitInsn(ICONST_5);
  2449. break;
  2450. }
  2451. }
  2452. else if (index > -127 && index < 128) {
  2453. assert debug("BIPUSH " + index);
  2454. mv.visitIntInsn(BIPUSH, index);
  2455. }
  2456. else if (index > Short.MAX_VALUE) {
  2457. assert debug("LDC " + index);
  2458. mv.visitLdcInsn(index);
  2459. }
  2460. else {
  2461. assert debug("SIPUSH " + index);
  2462. mv.visitIntInsn(SIPUSH, index);
  2463. }
  2464. }
  2465. public Accessor optimizeObjectCreation(ParserContext pCtx, char[] property, int start, int offset, Object ctx,
  2466. Object thisRef, VariableResolverFactory factory) {
  2467. _initJIT();
  2468. compiledInputs = new ArrayList<ExecutableStatement>();
  2469. this.start = cursor = start;
  2470. this.end = start + offset;
  2471. this.length = this.end - this.start;
  2472. this.ctx = ctx;
  2473. this.thisRef = thisRef;
  2474. this.variableFactory = factory;
  2475. this.pCtx = pCtx;
  2476. String[] cnsRes = captureContructorAndResidual(property, start, offset);
  2477. List<char[]> constructorParms = parseMethodOrConstructor(cnsRes[0].toCharArray());
  2478. try {
  2479. if (constructorParms != null) {
  2480. for (char[] constructorParm : constructorParms) {
  2481. compiledInputs.add((ExecutableStatement) subCompileExpression(constructorParm, pCtx));
  2482. }
  2483. Class cls = findClass(factory, new String(subset(property, 0, findFirst('(', start, length, property))), pCtx);
  2484. assert debug("NEW " + getInternalName(cls));
  2485. mv.visitTypeInsn(NEW, getInternalName(cls));
  2486. assert debug("DUP");
  2487. mv.visitInsn(DUP);
  2488. Object[] parms = new Object[constructorParms.size()];
  2489. int i = 0;
  2490. for (ExecutableStatement es : compiledInputs) {
  2491. parms[i++] = es.getValue(ctx, factory);
  2492. }
  2493. Constructor cns = getBestConstructorCandidate(parms, cls, pCtx.isStrongTyping());
  2494. if (cns == null) {
  2495. StringBuilder error = new StringBuilder();
  2496. for (int x = 0; x < parms.length; x++) {
  2497. error.append(parms[x].getClass().getName());
  2498. if (x + 1 < parms.length) error.append(", ");
  2499. }
  2500. throw new CompileException("unable to find constructor: " + cls.getName()
  2501. + "(" + error.toString() + ")", expr, st);
  2502. }
  2503. this.returnType = cns.getDeclaringClass();
  2504. Class tg;
  2505. for (i = 0; i < constructorParms.size(); i++) {
  2506. assert debug("ALOAD 0");
  2507. mv.visitVarInsn(ALOAD, 0);
  2508. assert debug("GETFIELD p" + i);
  2509. mv.visitFieldInsn(GETFIELD, className, "p" + i, "L" + NAMESPACE + "compiler/ExecutableStatement;");
  2510. assert debug("ALOAD 2");
  2511. mv.visitVarInsn(ALOAD, 2);
  2512. assert debug("ALOAD 3");
  2513. mv.visitVarInsn(ALOAD, 3);
  2514. assert debug("INVOKEINTERFACE " + NAMESPACE + "compiler/ExecutableStatement.getValue");
  2515. mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE
  2516. + "compiler/ExecutableStatement", "getValue", "(Ljava/lang/Object;L" + NAMESPACE
  2517. + "integration/VariableResolverFactory;)Ljava/lang/Object;");
  2518. tg = cns.getParameterTypes()[i].isPrimitive()
  2519. ? getWrapperClass(cns.getParameterTypes()[i]) : cns.getParameterTypes()[i];
  2520. if (parms[i] != null && !parms[i].getClass().isAssignableFrom(cns.getParameterTypes()[i])) {
  2521. ldcClassConstant(tg);
  2522. assert debug("INVOKESTATIC " + NAMESPACE + "DataConversion.convert");
  2523. mv.visitMethodInsn(INVOKESTATIC, "" + NAMESPACE + "DataConversion", "convert",
  2524. "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
  2525. if (cns.getParameterTypes()[i].isPrimitive()) {
  2526. unwrapPrimitive(cns.getParameterTypes()[i]);
  2527. }
  2528. else {
  2529. assert debug("CHECKCAST " + getInternalName(tg));
  2530. mv.visitTypeInsn(CHECKCAST, getInternalName(tg));
  2531. }
  2532. }
  2533. else {
  2534. assert debug("CHECKCAST " + getInternalName(cns.getParameterTypes()[i]));
  2535. mv.visitTypeInsn(CHECKCAST, getInternalName(cns.getParameterTypes()[i]));
  2536. }
  2537. }
  2538. assert debug("INVOKESPECIAL " + getInternalName(cls) + ".<init> : " + getConstructorDescriptor(cns));
  2539. mv.visitMethodInsn(INVOKESPECIAL, getInternalName(cls), "<init>", getConstructorDescriptor(cns));
  2540. _finishJIT();
  2541. Accessor acc = _initializeAccessor();
  2542. if (cnsRes.length > 1 && cnsRes[1] != null && !cnsRes[1].trim().equals("")) {
  2543. return new Union(acc, cnsRes[1].toCharArray(), 0, cnsRes[1].length());
  2544. }
  2545. return acc;
  2546. }
  2547. else {
  2548. Class cls = findClass(factory, new String(property), pCtx);
  2549. assert debug("NEW " + getInternalName(cls));
  2550. mv.visitTypeInsn(NEW, getInternalName(cls));
  2551. assert debug("DUP");
  2552. mv.visitInsn(DUP);
  2553. Constructor cns = cls.getConstructor(EMPTYCLS);
  2554. assert debug("INVOKESPECIAL <init>");
  2555. mv.visitMethodInsn(INVOKESPECIAL, getInternalName(cls), "<init>", getConstructorDescriptor(cns));
  2556. _finishJIT();
  2557. Accessor acc = _initializeAccessor();
  2558. if (cnsRes.length > 1 && cnsRes[1] != null && !cnsRes[1].trim().equals("")) {
  2559. return new Union(acc, cnsRes[1].toCharArray(), 0, cnsRes[1].length());
  2560. }
  2561. return acc;
  2562. }
  2563. }
  2564. catch (ClassNotFoundException e) {
  2565. throw new CompileException("class or class reference not found: "
  2566. + new String(property), property, st);
  2567. }
  2568. catch (Exception e) {
  2569. throw new OptimizationFailure("could not optimize construtor: " + new String(property), e);
  2570. }
  2571. }
  2572. public Class getEgressType() {
  2573. return returnType;
  2574. }
  2575. private void dumpAdvancedDebugging() {
  2576. if (buildLog == null) return;
  2577. System.out.println("JIT Compiler Dump for: <<" + (expr == null ? null : new String(expr))
  2578. + ">>\n-------------------------------\n");
  2579. System.out.println(buildLog.toString());
  2580. System.out.println("\n<END OF DUMP>\n");
  2581. if (MVEL.isFileDebugging()) {
  2582. try {
  2583. FileWriter writer = ParseTools.getDebugFileWriter();
  2584. writer.write(buildLog.toString());
  2585. writer.flush();
  2586. writer.close();
  2587. }
  2588. catch (IOException e) {
  2589. //empty
  2590. }
  2591. }
  2592. }
  2593. private Object propHandlerByteCode(String property, Object ctx, Class handler) {
  2594. PropertyHandler ph = getPropertyHandler(handler);
  2595. if (ph instanceof ProducesBytecode) {
  2596. assert debug("<<3rd-Party Code Generation>>");
  2597. ((ProducesBytecode) ph).produceBytecodeGet(mv, property, variableFactory);
  2598. return ph.getProperty(property, ctx, variableFactory);
  2599. }
  2600. else {
  2601. throw new RuntimeException("unable to compileShared: custom accessor does not support producing bytecode: "
  2602. + ph.getClass().getName());
  2603. }
  2604. }
  2605. private void propHandlerByteCodePut(String property, Object ctx, Class handler, Object value) {
  2606. PropertyHandler ph = getPropertyHandler(handler);
  2607. if (ph instanceof ProducesBytecode) {
  2608. assert debug("<<3rd-Party Code Generation>>");
  2609. ((ProducesBytecode) ph).produceBytecodePut(mv, property, variableFactory);
  2610. ph.setProperty(property, ctx, variableFactory, value);
  2611. }
  2612. else {
  2613. throw new RuntimeException("unable to compileShared: custom accessor does not support producing bytecode: "
  2614. + ph.getClass().getName());
  2615. }
  2616. }
  2617. private void writeOutNullHandler(Member member, int type) {
  2618. assert debug("DUP");
  2619. mv.visitInsn(DUP);
  2620. Label j = new Label();
  2621. assert debug("IFNONNULL : jump");
  2622. mv.visitJumpInsn(IFNONNULL, j);
  2623. assert debug("POP");
  2624. mv.visitInsn(POP);
  2625. assert debug("ALOAD 0");
  2626. mv.visitVarInsn(ALOAD, 0);
  2627. if (type == 0) {
  2628. this.propNull = true;
  2629. assert debug("GETFIELD 'nullPropertyHandler'");
  2630. mv.visitFieldInsn(GETFIELD, className, "nullPropertyHandler", "L" + NAMESPACE + "integration/PropertyHandler;");
  2631. }
  2632. else {
  2633. this.methNull = true;
  2634. assert debug("GETFIELD 'nullMethodHandler'");
  2635. mv.visitFieldInsn(GETFIELD, className, "nullMethodHandler", "L" + NAMESPACE + "integration/PropertyHandler;");
  2636. }
  2637. assert debug("LDC '" + member.getName() + "'");
  2638. mv.visitLdcInsn(member.getName());
  2639. assert debug("ALOAD 1");
  2640. mv.visitVarInsn(ALOAD, 1);
  2641. assert debug("ALOAD 3");
  2642. mv.visitVarInsn(ALOAD, 3);
  2643. assert debug("INVOKEINTERFACE PropertyHandler.getProperty");
  2644. mv.visitMethodInsn(INVOKEINTERFACE, NAMESPACE + "integration/PropertyHandler", "getProperty",
  2645. "(Ljava/lang/String;Ljava/lang/Object;L" + NAMESPACE + "integration/VariableResolverFactory;)Ljava/lang/Object;");
  2646. assert debug("LABEL:jump");
  2647. mv.visitLabel(j);
  2648. }
  2649. public boolean isLiteralOnly() {
  2650. return literal;
  2651. }
  2652. }