Java tutorial
/** * * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * **/ package lucee.transformer.bytecode; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import lucee.transformer.bytecode.expression.Expression; import lucee.transformer.bytecode.literal.LitString; import lucee.transformer.bytecode.statement.PrintOut; import lucee.transformer.bytecode.statement.StatementBaseNoFinal; import lucee.transformer.bytecode.util.ASMUtil; import lucee.transformer.bytecode.util.ExpressionUtil; import lucee.transformer.bytecode.util.Types; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; /** * Base Body implementation */ public class BodyBase extends StatementBaseNoFinal implements Body { private static long counter = 0; private LinkedList<Statement> statements = new LinkedList<Statement>(); private Statement last = null; //private int count=-1; private final static int MAX_STATEMENTS = 206; /** * Constructor of the class */ public BodyBase() { super(null, null); } /** * * @see lucee.transformer.bytecode.Body#addStatement(lucee.transformer.bytecode.Statement) */ public void addStatement(Statement statement) { if (statement instanceof PrintOut) { Expression expr = ((PrintOut) statement).getExpr(); if (expr instanceof LitString && concatPrintouts(((LitString) expr).getString())) return; } statement.setParent(this); this.statements.add(statement); last = statement; } public void addFirst(Statement statement) { statement.setParent(this); this.statements.add(0, statement); } public void remove(Statement statement) { statement.setParent(null); this.statements.remove(statement); } /** * * @see lucee.transformer.bytecode.Body#getStatements() */ public List<Statement> getStatements() { return statements; } public boolean hasStatements() { return !statements.isEmpty(); } /** * * @see lucee.transformer.bytecode.Body#moveStatmentsTo(lucee.transformer.bytecode.Body) */ public void moveStatmentsTo(Body trg) { Iterator<Statement> it = statements.iterator(); while (it.hasNext()) { Statement stat = it.next(); stat.setParent(trg); trg.getStatements().add(stat); } statements.clear(); } public void addPrintOut(String str, Position start, Position end) { if (concatPrintouts(str)) return; last = new PrintOut(new LitString(str, start, end), start, end); last.setParent(this); this.statements.add(last); } private boolean concatPrintouts(String str) { if (last instanceof PrintOut) { PrintOut po = (PrintOut) last; Expression expr = po.getExpr(); if (expr instanceof LitString) { LitString lit = (LitString) expr; if (lit.getString().length() < 1024) { po.setExpr(LitString.toExprString(lit.getString().concat(str), lit.getStart(), lit.getEnd())); return true; } } } return false; } public void _writeOut(BytecodeContext bc) throws BytecodeException { writeOut(bc, this); } public static void writeOut(final BytecodeContext bc, Body body) throws BytecodeException { writeOut(bc, body.getStatements()); } public static void writeOut(final BytecodeContext bc, List<Statement> statements) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); boolean isOutsideMethod; GeneratorAdapter a = null; Method m; BytecodeContext _bc = bc; Iterator<Statement> it = statements.iterator(); boolean split = bc.getPage().getSplitIfNecessary(); //int lastLine=-1; while (it.hasNext()) { isOutsideMethod = bc.getMethod().getReturnType().equals(Types.VOID); Statement s = it.next(); if (split && _bc.incCount() > MAX_STATEMENTS && bc.doSubFunctions() && (isOutsideMethod || !s.hasFlowController()) && s.getStart() != null) { if (a != null) { a.returnValue(); a.endMethod(); } //ExpressionUtil.visitLine(bc, s.getLine()); String method = ASMUtil.createOverfowMethod(bc.getMethod().getName(), bc.getPage().getMethodCount()); ExpressionUtil.visitLine(bc, s.getStart()); //ExpressionUtil.lastLine(bc); m = new Method(method, Types.VOID, new Type[] { Types.PAGE_CONTEXT }); a = new GeneratorAdapter(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, m, null, new Type[] { Types.THROWABLE }, bc.getClassWriter()); _bc = new BytecodeContext(bc.getStaticConstructor(), bc.getConstructor(), bc.getKeys(), bc, a, m); if (bc.getRoot() != null) _bc.setRoot(bc.getRoot()); else _bc.setRoot(bc); adapter.visitVarInsn(Opcodes.ALOAD, 0); adapter.visitVarInsn(Opcodes.ALOAD, 1); adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, bc.getClassName(), method, "(Llucee/runtime/PageContext;)V"); } if (_bc != bc && s.hasFlowController()) { if (a != null) { a.returnValue(); a.endMethod(); } _bc = bc; a = null; } ExpressionUtil.writeOut(s, _bc); } if (a != null) { a.returnValue(); a.endMethod(); } } public static void writeOutNew(final BytecodeContext bc, List<Statement> statements) throws BytecodeException { if (statements == null || statements.size() == 0) return; Statement s; Iterator<Statement> it = statements.iterator(); boolean isVoidMethod = bc.getMethod().getReturnType().equals(Types.VOID); boolean split = bc.getPage().getSplitIfNecessary(); // split if (split && isVoidMethod && statements.size() > 1 && bc.doSubFunctions()) { int collectionSize = statements.size() / 10; if (collectionSize < 1) collectionSize = 1; List<Statement> _statements = new ArrayList<Statement>(); while (it.hasNext()) { s = it.next(); if (s.hasFlowController()) { // add existing statements to sub method if (_statements.size() > 0) { addToSubMethod(bc, _statements.toArray(new Statement[_statements.size()])); _statements.clear(); } ExpressionUtil.writeOut(s, bc); } else { _statements.add(s); if (_statements.size() >= collectionSize) { if (_statements.size() <= 10 && ASMUtil.count(_statements, true) <= 20) { Iterator<Statement> _it = _statements.iterator(); while (_it.hasNext()) ExpressionUtil.writeOut(_it.next(), bc); } else addToSubMethod(bc, _statements.toArray(new Statement[_statements.size()])); _statements.clear(); } } } if (_statements.size() > 0) addToSubMethod(bc, _statements.toArray(new Statement[_statements.size()])); } // no split else { while (it.hasNext()) { ExpressionUtil.writeOut(it.next(), bc); } } } private static void addToSubMethod(BytecodeContext bc, Statement... statements) throws BytecodeException { if (statements == null || statements.length == 0) return; GeneratorAdapter adapter = bc.getAdapter(); String method = ASMUtil.createOverfowMethod(bc.getMethod().getName(), bc.getPage().getMethodCount()); for (int i = 0; i < statements.length; i++) { if (statements[i].getStart() != null) { ExpressionUtil.visitLine(bc, statements[i].getStart()); break; } } //ExpressionUtil.lastLine(bc); Method m = new Method(method, Types.VOID, new Type[] { Types.PAGE_CONTEXT }); GeneratorAdapter a = new GeneratorAdapter(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, m, null, new Type[] { Types.THROWABLE }, bc.getClassWriter()); BytecodeContext _bc = new BytecodeContext(bc.getStaticConstructor(), bc.getConstructor(), bc.getKeys(), bc, a, m); if (bc.getRoot() != null) _bc.setRoot(bc.getRoot()); else _bc.setRoot(bc); adapter.visitVarInsn(Opcodes.ALOAD, 0); adapter.visitVarInsn(Opcodes.ALOAD, 1); adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, bc.getClassName(), method, "(Llucee/runtime/PageContext;)V"); for (int i = 0; i < statements.length; i++) { ExpressionUtil.writeOut(statements[i], _bc); } a.returnValue(); a.endMethod(); } public static synchronized String id() { counter++; if (counter < 0) counter = 1; return Long.toString(counter, Character.MAX_RADIX); } /** * * @see lucee.transformer.bytecode.Body#isEmpty() */ public boolean isEmpty() { return statements.isEmpty(); } }