package org.elasticsearch.plan.a; /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTree; import org.objectweb.asm.*; import static org.elasticsearch.plan.a.Adapter.*; import static org.elasticsearch.plan.a.Definition.*; import static org.elasticsearch.plan.a.PlanAParser.*; class Writer extends PlanABaseVisitor<Void> { final static String BASE_CLASS_NAME = Executable.class.getName(); final static String CLASS_NAME = BASE_CLASS_NAME + "$CompiledPlanAExecutable"; final static String BASE_CLASS_INTERNAL = Executable.class.getName().replace('.', '/'); final static String CLASS_INTERNAL = BASE_CLASS_INTERNAL + "$CompiledPlanAExecutable"; static byte[] write(Adapter adapter) { Writer writer = new Writer(adapter); return writer.getBytes(); } private final Adapter adapter; private final Caster caster; private final ParseTree root; private final String source; private ClassWriter writer; private MethodVisitor execute; private Writer(final Adapter adapter) { this.adapter = adapter; caster = adapter.caster; root = adapter.root; source = adapter.source; writeBegin(); writeConstructor(); writeExecute(); writeEnd(); } private void writeBegin() { final int compute = ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS; final int version = Opcodes.V1_7; final int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC; final String base = BASE_CLASS_INTERNAL; final String name = CLASS_INTERNAL; writer = new ClassWriter(compute); writer.visit(version, access, name, null, base, null); writer.visitSource(source, null); } private void writeConstructor() { final int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC; final String aname = "<init>"; final String adescriptor = "(Ljava/lang/String;Ljava/lang/String;)V"; final MethodVisitor constructor = writer.visitMethod(access, aname, adescriptor, null, null); constructor.visitCode(); constructor.visitVarInsn(Opcodes.ALOAD, 0); constructor.visitVarInsn(Opcodes.ALOAD, 1); constructor.visitVarInsn(Opcodes.ALOAD, 2); constructor.visitMethodInsn(Opcodes.INVOKESPECIAL, BASE_CLASS_INTERNAL, aname, adescriptor, false); constructor.visitInsn(Opcodes.RETURN); constructor.visitMaxs(0, 0); constructor.visitEnd(); } private void writeExecute() { final int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC; final String name = "execute"; final String descriptor = "(Ljava/util/Map;)Ljava/lang/Object;"; final String signature = "(Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;)Ljava/lang/Object;"; execute = writer.visitMethod(access, name, descriptor, signature, null); execute.visitCode(); visit(root); execute.visitMaxs(0, 0); execute.visitEnd(); } @Override public Void visitSource(final SourceContext ctx) { final StatementMetadata sourcesmd = adapter.getStatementMetadata(ctx); for (final StatementContext sctx : ctx.statement()) { visit(sctx); } if (!sourcesmd.allReturn) { execute.visitInsn(Opcodes.ACONST_NULL); execute.visitInsn(Opcodes.ARETURN); } return null; } @Override public Void visitIf(final IfContext ctx) { final ExpressionContext exprctx = ctx.expression(); final boolean els = ctx.ELSE() != null; final Branch branch = adapter.markBranch(ctx, exprctx); branch.end = new Label(); branch.fals = els ? new Label() : branch.end; visit(exprctx); final BlockContext blockctx0 = ctx.block(0); final StatementMetadata blockmd0 = adapter.getStatementMetadata(blockctx0); visit(blockctx0); if (els) { if (!blockmd0.allExit) { execute.visitJumpInsn(Opcodes.GOTO, branch.end); } execute.visitLabel(branch.fals); visit(ctx.block(1)); } execute.visitLabel(branch.end); return null; } @Override public Void visitWhile(final WhileContext ctx) { final ExpressionContext exprctx = ctx.expression(); final Branch branch = adapter.markBranch(ctx, exprctx); branch.begin = new Label(); branch.end = new Label(); branch.fals = branch.end; adapter.pushJump(branch); execute.visitLabel(branch.begin); visit(exprctx); final BlockContext blockctx = ctx.block(); boolean allexit = false; if (blockctx != null) { StatementMetadata blocksmd = adapter.getStatementMetadata(blockctx); allexit = blocksmd.allExit; visit(blockctx); } if (!allexit) { execute.visitJumpInsn(Opcodes.GOTO, branch.begin); } execute.visitLabel(branch.end); adapter.popJump(); return null; } @Override public Void visitDo(final DoContext ctx) { final ExpressionContext exprctx = ctx.expression(); final Branch branch = adapter.markBranch(ctx, exprctx); branch.begin = new Label(); branch.end = new Label(); branch.fals = branch.end; adapter.pushJump(branch); execute.visitLabel(branch.begin); final BlockContext bctx = ctx.block(); final StatementMetadata blocksmd = adapter.getStatementMetadata(bctx); visit(bctx); visit(exprctx); if (!blocksmd.allExit) { execute.visitJumpInsn(Opcodes.GOTO, branch.begin); } execute.visitLabel(branch.end); adapter.popJump(); return null; } @Override public Void visitFor(final ForContext ctx) { final ExpressionContext exprctx0 = ctx.expression(0); final ExpressionContext exprctx1 = ctx.expression(1); final Branch branch = adapter.markBranch(ctx, exprctx0); final Label start = new Label(); branch.begin = exprctx1 == null ? start : new Label(); branch.end = new Label(); branch.fals = branch.end; adapter.pushJump(branch); if (ctx.declaration() != null) { visit(ctx.declaration()); } execute.visitLabel(start); if (exprctx0 != null) { visit(exprctx0); } final BlockContext blockctx = ctx.block(); boolean allexit = false; if (blockctx != null) { StatementMetadata blocksmd = adapter.getStatementMetadata(blockctx); allexit = blocksmd.allExit; visit(blockctx); } if (exprctx1 != null) { execute.visitLabel(branch.begin); visit(exprctx1); } if (exprctx1 != null || !allexit) { execute.visitJumpInsn(Opcodes.GOTO, start); } execute.visitLabel(branch.end); adapter.popJump(); return null; } @Override public Void visitDecl(final DeclContext ctx) { visit(ctx.declaration()); return null; } @Override public Void visitContinue(final ContinueContext ctx) { final Branch jump = adapter.peekJump(); execute.visitJumpInsn(Opcodes.GOTO, jump.begin); return null; } @Override public Void visitBreak(final BreakContext ctx) { final Branch jump = adapter.peekJump(); execute.visitJumpInsn(Opcodes.GOTO, jump.end); return null; } @Override public Void visitReturn(final ReturnContext ctx) { visit(ctx.expression()); execute.visitInsn(Opcodes.ARETURN); return null; } @Override public Void visitExpr(final ExprContext ctx) { visit(ctx.expression()); return null; } @Override public Void visitMultiple(final MultipleContext ctx) { for (final StatementContext sctx : ctx.statement()) { visit(sctx); } return null; } @Override public Void visitSingle(final SingleContext ctx) { visit(ctx.statement()); return null; } @Override public Void visitEmpty(final EmptyContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitDeclaration(DeclarationContext ctx) { for (final DeclvarContext declctx : ctx.declvar()) { visit(declctx); } return null; } @Override public Void visitDecltype(final DecltypeContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitDeclvar(final DeclvarContext ctx) { final ExpressionMetadata declemd = adapter.getExpressionMetadata(ctx); final Variable variable = (Variable)declemd.postConst; final ExpressionContext exprctx = ctx.expression(); final boolean initialize = exprctx == null; if (!initialize) { visit(exprctx); } switch (variable.type.metadata) { case VOID: throw new IllegalStateException(error(ctx) + "Unexpected writer state."); case BOOL: case BYTE: case SHORT: case CHAR: case INT: if (initialize) writeNumeric(ctx, 0); execute.visitVarInsn(Opcodes.ISTORE, variable.slot); break; case LONG: if (initialize) writeNumeric(ctx, 0L); execute.visitVarInsn(Opcodes.LSTORE, variable.slot); break; case FLOAT: if (initialize) writeNumeric(ctx, 0.0F); execute.visitVarInsn(Opcodes.FSTORE, variable.slot); break; case DOUBLE: if (initialize) writeNumeric(ctx, 0.0); execute.visitVarInsn(Opcodes.DSTORE, variable.slot); break; default: if (initialize) { execute.visitInsn(Opcodes.ACONST_NULL); } execute.visitVarInsn(Opcodes.ASTORE, variable.slot); } return null; } @Override public Void visitPrecedence(final PrecedenceContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitNumeric(final NumericContext ctx) { final ExpressionMetadata numericemd = adapter.getExpressionMetadata(ctx); final Object postConst = numericemd.postConst; if (postConst == null) { writeNumeric(ctx, numericemd.preConst); caster.checkWriteCast(execute, numericemd); } else { writeConstant(ctx, postConst); } adapter.checkWriteBranch(execute, ctx); return null; } @Override public Void visitString(final StringContext ctx) { final ExpressionMetadata stringemd = adapter.getExpressionMetadata(ctx); final Object postConst = stringemd.postConst; if (postConst == null) { writeString(ctx, stringemd.preConst); caster.checkWriteCast(execute, stringemd); } else { writeConstant(ctx, postConst); } adapter.checkWriteBranch(execute, ctx); return null; } @Override public Void visitChar(final CharContext ctx) { final ExpressionMetadata charemd = adapter.getExpressionMetadata(ctx); final Object postConst = charemd.postConst; if (postConst == null) { writeNumeric(ctx, (int)(char)charemd.preConst); caster.checkWriteCast(execute, charemd); } else { writeConstant(ctx, postConst); } adapter.checkWriteBranch(execute, ctx); return null; } @Override public Void visitTrue(final TrueContext ctx) { final ExpressionMetadata trueemd = adapter.getExpressionMetadata(ctx); final Object postConst = trueemd.postConst; final Branch branch = adapter.getBranch(ctx); if (branch == null) { if (postConst == null) { writeBoolean(ctx, true); caster.checkWriteCast(execute, trueemd); } else { writeConstant(ctx, postConst); } } else if (branch.tru != null) { execute.visitJumpInsn(Opcodes.GOTO, branch.tru); } return null; } @Override public Void visitFalse(final FalseContext ctx) { final ExpressionMetadata falseemd = adapter.getExpressionMetadata(ctx); final Object postConst = falseemd.postConst; final Branch branch = adapter.getBranch(ctx); if (branch == null) { if (postConst == null) { writeBoolean(ctx, false); caster.checkWriteCast(execute, falseemd); } else { writeConstant(ctx, postConst); } } else if (branch.fals != null) { execute.visitJumpInsn(Opcodes.GOTO, branch.fals); } return null; } @Override public Void visitNull(final NullContext ctx) { final ExpressionMetadata nullemd = adapter.getExpressionMetadata(ctx); execute.visitInsn(Opcodes.ACONST_NULL); caster.checkWriteCast(execute, nullemd); adapter.checkWriteBranch(execute, ctx); return null; } @Override public Void visitCat(CatContext ctx) { final ExpressionMetadata catemd = adapter.getExpressionMetadata(ctx); final boolean strings = adapter.getStrings(ctx); if (catemd.postConst != null) { writeConstant(ctx, catemd.postConst); } else { if (!strings) { writeNewStrings(); } final ExpressionContext exprctx0 = ctx.expression(0); final ExpressionMetadata expremd0 = adapter.getExpressionMetadata(exprctx0); adapter.markStrings(exprctx0); visit(exprctx0); if (adapter.getStrings(exprctx0)) { writeAppendStrings(ctx, expremd0.to.metadata); adapter.unmarkStrings(exprctx0); } final ExpressionContext exprctx1 = ctx.expression(1); final ExpressionMetadata expremd1 = adapter.getExpressionMetadata(exprctx1); adapter.markStrings(exprctx1); visit(exprctx1); if (adapter.getStrings(exprctx1)) { writeAppendStrings(ctx, expremd1.to.metadata); adapter.unmarkStrings(exprctx1); } if (strings) { adapter.unmarkStrings(ctx); } else { writeToStrings(); } caster.checkWriteCast(execute, catemd); } adapter.checkWriteBranch(execute, ctx); return null; } @Override public Void visitExt(final ExtContext ctx) { final External external = adapter.getExternal(ctx); external.setWriter(this, execute); external.write(ctx); return null; } @Override public Void visitPostinc(final PostincContext ctx) { final External external = adapter.getExternal(ctx); external.setWriter(this, execute); external.write(ctx); return null; } @Override public Void visitPreinc(final PreincContext ctx) { final External external = adapter.getExternal(ctx); external.setWriter(this, execute); external.write(ctx); return null; } @Override public Void visitUnary(final UnaryContext ctx) { final ExpressionMetadata unaryemd = adapter.getExpressionMetadata(ctx); final Object postConst = unaryemd.postConst; final Object preConst = unaryemd.preConst; final Branch branch = adapter.getBranch(ctx); if (postConst != null) { if (ctx.BOOLNOT() != null) { if (branch == null) { writeConstant(ctx, postConst); } else { if ((boolean)postConst && branch.tru != null) { execute.visitJumpInsn(Opcodes.GOTO, branch.tru); } else if (!(boolean)postConst && branch.fals != null) { execute.visitJumpInsn(Opcodes.GOTO, branch.fals); } } } else { writeConstant(ctx, postConst); adapter.checkWriteBranch(execute, ctx); } } else if (preConst != null) { if (branch == null) { writeConstant(ctx, preConst); caster.checkWriteCast(execute, unaryemd); } else { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); } } else { final ExpressionContext exprctx = ctx.expression(); if (ctx.BOOLNOT() != null) { final Branch local = adapter.markBranch(ctx, exprctx); if (branch == null) { local.fals = new Label(); final Label aend = new Label(); visit(exprctx); execute.visitInsn(Opcodes.ICONST_0); execute.visitJumpInsn(Opcodes.GOTO, aend); execute.visitLabel(local.fals); execute.visitInsn(Opcodes.ICONST_1); execute.visitLabel(aend); caster.checkWriteCast(execute, unaryemd); } else { local.tru = branch.fals; local.fals = branch.tru; visit(exprctx); } } else { final TypeMetadata metadata = unaryemd.from.metadata; visit(exprctx); if (ctx.BWNOT() != null) { if (metadata == TypeMetadata.INT) { writeConstant(ctx, -1); execute.visitInsn(Opcodes.IXOR); } else if (metadata == TypeMetadata.LONG) { writeConstant(ctx, -1L); execute.visitInsn(Opcodes.LXOR); } else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } } else if (ctx.SUB() != null) { if (metadata == TypeMetadata.INT) execute.visitInsn(Opcodes.INEG); else if (metadata == TypeMetadata.LONG) execute.visitInsn(Opcodes.LNEG); else if (metadata == TypeMetadata.FLOAT) execute.visitInsn(Opcodes.FNEG); else if (metadata == TypeMetadata.DOUBLE) execute.visitInsn(Opcodes.DNEG); else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } } caster.checkWriteCast(execute, unaryemd); adapter.checkWriteBranch(execute, ctx); } } return null; } @Override public Void visitCast(final CastContext ctx) { final ExpressionMetadata castemd = adapter.getExpressionMetadata(ctx); final Object postConst = castemd.postConst; if (postConst == null) { visit(ctx.expression()); caster.checkWriteCast(execute, castemd); } else { writeConstant(ctx, postConst); } adapter.checkWriteBranch(execute, ctx); return null; } @Override public Void visitBinary(final BinaryContext ctx) { final ExpressionMetadata binaryemd = adapter.getExpressionMetadata(ctx); final Object postConst = binaryemd.postConst; final Object preConst = binaryemd.preConst; final Branch branch = adapter.getBranch(ctx); if (postConst != null) { writeConstant(ctx, postConst); } else if (preConst != null) { if (branch == null) { writeConstant(ctx, preConst); caster.checkWriteCast(execute, binaryemd); } else { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); } } else { writeConstant(ctx, postConst); final ExpressionContext expr0 = ctx.expression(0); final ExpressionContext expr1 = ctx.expression(1); visit(expr0); visit(expr1); final TypeMetadata metadata = binaryemd.from.metadata; // if its a 64-bit shift, fixup the last argument to truncate to 32-bits // note unlike java, this means we still do binary promotion of shifts, // but it keeps things simple if (ctx.LSH() != null || ctx.USH() != null || ctx.RSH() != null) { // if expr1 is 64 bits ExpressionMetadata arg = adapter.getExpressionMetadata(expr1); if (arg.cast.to.metadata == TypeMetadata.LONG) { execute.visitInsn(Opcodes.L2I); } } if (ctx.MUL() != null) writeBinaryInstruction(ctx, metadata, MUL); else if (ctx.DIV() != null) writeBinaryInstruction(ctx, metadata, DIV); else if (ctx.REM() != null) writeBinaryInstruction(ctx, metadata, REM); else if (ctx.SUB() != null) writeBinaryInstruction(ctx, metadata, SUB); else if (ctx.LSH() != null) writeBinaryInstruction(ctx, metadata, LSH); else if (ctx.USH() != null) writeBinaryInstruction(ctx, metadata, USH); else if (ctx.RSH() != null) writeBinaryInstruction(ctx, metadata, RSH); else if (ctx.BWAND() != null) writeBinaryInstruction(ctx, metadata, BWAND); else if (ctx.BWXOR() != null) writeBinaryInstruction(ctx, metadata, BWXOR); else if (ctx.BWOR() != null) writeBinaryInstruction(ctx, metadata, BWOR); else if (ctx.ADD() != null) writeBinaryInstruction(ctx, metadata, ADD); else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } caster.checkWriteCast(execute, binaryemd); } adapter.checkWriteBranch(execute, ctx); return null; } @Override public Void visitComp(final CompContext ctx) { final ExpressionMetadata compemd = adapter.getExpressionMetadata(ctx); final Object postConst = compemd.postConst; final Object preConst = compemd.preConst; final Branch branch = adapter.getBranch(ctx); if (postConst != null) { if (branch == null) { writeConstant(ctx, postConst); } else { if ((boolean)postConst && branch.tru != null) { execute.visitLabel(branch.tru); } else if (!(boolean)postConst && branch.fals != null) { execute.visitLabel(branch.fals); } } } else if (preConst != null) { if (branch == null) { writeConstant(ctx, preConst); caster.checkWriteCast(execute, compemd); } else { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); } } else { final ExpressionContext exprctx0 = ctx.expression(0); final ExpressionMetadata expremd0 = adapter.getExpressionMetadata(exprctx0); final ExpressionContext exprctx1 = ctx.expression(1); final ExpressionMetadata expremd1 = adapter.getExpressionMetadata(exprctx1); final TypeMetadata tmd1 = expremd1.to.metadata; visit(exprctx0); if (!expremd1.isNull) { visit(exprctx1); } final boolean tru = branch != null && branch.tru != null; final boolean fals = branch != null && branch.fals != null; final Label jump = tru ? branch.tru : fals ? branch.fals : new Label(); final Label end = new Label(); final boolean eq = (ctx.EQ() != null || ctx.EQR() != null) && (tru || !fals) || (ctx.NE() != null || ctx.NER() != null) && fals; final boolean ne = (ctx.NE() != null || ctx.NER() != null) && (tru || !fals) || (ctx.EQ() != null || ctx.EQR() != null) && fals; final boolean lt = ctx.LT() != null && (tru || !fals) || ctx.GTE() != null && fals; final boolean lte = ctx.LTE() != null && (tru || !fals) || ctx.GT() != null && fals; final boolean gt = ctx.GT() != null && (tru || !fals) || ctx.LTE() != null && fals; final boolean gte = ctx.GTE() != null && (tru || !fals) || ctx.LT() != null && fals; boolean eqobj = false; switch (tmd1) { case VOID: throw new IllegalStateException(error(ctx) + "Unexpected writer state."); case BOOL: if (eq) execute.visitJumpInsn(Opcodes.IF_ICMPEQ, jump); else if (ne) execute.visitJumpInsn(Opcodes.IF_ICMPNE, jump); else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } break; case BYTE: case SHORT: case CHAR: throw new IllegalStateException(error(ctx) + "Unexpected writer state."); case INT: if (eq) execute.visitJumpInsn(Opcodes.IF_ICMPEQ, jump); else if (ne) execute.visitJumpInsn(Opcodes.IF_ICMPNE, jump); else if (lt) execute.visitJumpInsn(Opcodes.IF_ICMPLT, jump); else if (lte) execute.visitJumpInsn(Opcodes.IF_ICMPLE, jump); else if (gt) execute.visitJumpInsn(Opcodes.IF_ICMPGT, jump); else if (gte) execute.visitJumpInsn(Opcodes.IF_ICMPGE, jump); else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } break; case LONG: execute.visitInsn(Opcodes.LCMP); if (eq) execute.visitJumpInsn(Opcodes.IFEQ, jump); else if (ne) execute.visitJumpInsn(Opcodes.IFNE, jump); else if (lt) execute.visitJumpInsn(Opcodes.IFLT, jump); else if (lte) execute.visitJumpInsn(Opcodes.IFLE, jump); else if (gt) execute.visitJumpInsn(Opcodes.IFGT, jump); else if (gte) execute.visitJumpInsn(Opcodes.IFGE, jump); else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } break; case FLOAT: if (eq) { execute.visitInsn(Opcodes.FCMPL); execute.visitJumpInsn(Opcodes.IFEQ, jump); } else if (ne) { execute.visitInsn(Opcodes.FCMPL); execute.visitJumpInsn(Opcodes.IFNE, jump); } else if (lt) { execute.visitInsn(Opcodes.FCMPG); execute.visitJumpInsn(Opcodes.IFLT, jump); } else if (lte) { execute.visitInsn(Opcodes.FCMPG); execute.visitJumpInsn(Opcodes.IFLE, jump); } else if (gt) { execute.visitInsn(Opcodes.FCMPL); execute.visitJumpInsn(Opcodes.IFGT, jump); } else if (gte) { execute.visitInsn(Opcodes.FCMPL); execute.visitJumpInsn(Opcodes.IFGE, jump); } else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } break; case DOUBLE: if (eq) { execute.visitInsn(Opcodes.DCMPL); execute.visitJumpInsn(Opcodes.IFEQ, jump); } else if (ne) { execute.visitInsn(Opcodes.DCMPL); execute.visitJumpInsn(Opcodes.IFNE, jump); } else if (lt) { execute.visitInsn(Opcodes.DCMPG); execute.visitJumpInsn(Opcodes.IFLT, jump); } else if (lte) { execute.visitInsn(Opcodes.DCMPG); execute.visitJumpInsn(Opcodes.IFLE, jump); } else if (gt) { execute.visitInsn(Opcodes.DCMPL); execute.visitJumpInsn(Opcodes.IFGT, jump); } else if (gte) { execute.visitInsn(Opcodes.DCMPL); execute.visitJumpInsn(Opcodes.IFGE, jump); } else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } break; default: if (eq) { if (expremd1.isNull) { execute.visitJumpInsn(Opcodes.IFNULL, jump); } else if (!expremd0.isNull && ctx.EQ() != null) { execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false); if (branch != null) { execute.visitJumpInsn(Opcodes.IFNE, jump); } eqobj = true; } else { execute.visitJumpInsn(Opcodes.IF_ACMPEQ, jump); } } else if (ne) { if (expremd1.isNull) { execute.visitJumpInsn(Opcodes.IFNONNULL, jump); } else if (!expremd0.isNull && ctx.NE() != null) { execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false); execute.visitJumpInsn(Opcodes.IFEQ, jump); } else { execute.visitJumpInsn(Opcodes.IF_ACMPNE, jump); } } else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } } if (branch == null) { if (!eqobj) { execute.visitInsn(Opcodes.ICONST_0); execute.visitJumpInsn(Opcodes.GOTO, end); execute.visitLabel(jump); execute.visitInsn(Opcodes.ICONST_1); execute.visitLabel(end); } caster.checkWriteCast(execute, compemd); } } return null; } @Override public Void visitBool(final BoolContext ctx) { final ExpressionMetadata boolemd = adapter.getExpressionMetadata(ctx); final Object postConst = boolemd.postConst; final Object preConst = boolemd.preConst; final Branch branch = adapter.getBranch(ctx); if (postConst != null) { if (branch == null) { writeConstant(ctx, postConst); } else { if ((boolean)postConst && branch.tru != null) { execute.visitLabel(branch.tru); } else if (!(boolean)postConst && branch.fals != null) { execute.visitLabel(branch.fals); } } } else if (preConst != null) { if (branch == null) { writeConstant(ctx, preConst); caster.checkWriteCast(execute, boolemd); } else { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); } } else { final ExpressionContext exprctx0 = ctx.expression(0); final ExpressionContext exprctx1 = ctx.expression(1); if (branch == null) { if (ctx.BOOLAND() != null) { final Branch local = adapter.markBranch(ctx, exprctx0, exprctx1); local.fals = new Label(); final Label end = new Label(); visit(exprctx0); visit(exprctx1); execute.visitInsn(Opcodes.ICONST_1); execute.visitJumpInsn(Opcodes.GOTO, end); execute.visitLabel(local.fals); execute.visitInsn(Opcodes.ICONST_0); execute.visitLabel(end); } else if (ctx.BOOLOR() != null) { final Branch branch0 = adapter.markBranch(ctx, exprctx0); branch0.tru = new Label(); final Branch branch1 = adapter.markBranch(ctx, exprctx1); branch1.fals = new Label(); final Label aend = new Label(); visit(exprctx0); visit(exprctx1); execute.visitLabel(branch0.tru); execute.visitInsn(Opcodes.ICONST_1); execute.visitJumpInsn(Opcodes.GOTO, aend); execute.visitLabel(branch1.fals); execute.visitInsn(Opcodes.ICONST_0); execute.visitLabel(aend); } else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } caster.checkWriteCast(execute, boolemd); } else { if (ctx.BOOLAND() != null) { final Branch branch0 = adapter.markBranch(ctx, exprctx0); branch0.fals = branch.fals == null ? new Label() : branch.fals; final Branch branch1 = adapter.markBranch(ctx, exprctx1); branch1.tru = branch.tru; branch1.fals = branch.fals; visit(exprctx0); visit(exprctx1); if (branch.fals == null) { execute.visitLabel(branch0.fals); } } else if (ctx.BOOLOR() != null) { final Branch branch0 = adapter.markBranch(ctx, exprctx0); branch0.tru = branch.tru == null ? new Label() : branch.tru; final Branch branch1 = adapter.markBranch(ctx, exprctx1); branch1.tru = branch.tru; branch1.fals = branch.fals; visit(exprctx0); visit(exprctx1); if (branch.tru == null) { execute.visitLabel(branch0.tru); } } else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } } } return null; } @Override public Void visitConditional(final ConditionalContext ctx) { final ExpressionMetadata condemd = adapter.getExpressionMetadata(ctx); final Branch branch = adapter.getBranch(ctx); final ExpressionContext expr0 = ctx.expression(0); final ExpressionContext expr1 = ctx.expression(1); final ExpressionContext expr2 = ctx.expression(2); final Branch local = adapter.markBranch(ctx, expr0); local.fals = new Label(); local.end = new Label(); visit(expr0); visit(expr1); execute.visitJumpInsn(Opcodes.GOTO, local.end); execute.visitLabel(local.fals); visit(expr2); execute.visitLabel(local.end); if (branch == null) { caster.checkWriteCast(execute, condemd); } return null; } @Override public Void visitAssignment(final AssignmentContext ctx) { final External external = adapter.getExternal(ctx); external.setWriter(this, execute); external.write(ctx); return null; } @Override public Void visitExtstart(ExtstartContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitExtprec(final ExtprecContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitExtcast(final ExtcastContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitExtbrace(final ExtbraceContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitExtdot(final ExtdotContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitExttype(final ExttypeContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitExtcall(final ExtcallContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitExtmember(final ExtmemberContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitArguments(final ArgumentsContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); } @Override public Void visitIncrement(IncrementContext ctx) { final ExpressionMetadata incremd = adapter.getExpressionMetadata(ctx); final Object postConst = incremd.postConst; if (postConst == null) { writeString(ctx, incremd.preConst); caster.checkWriteCast(execute, incremd); } else { writeConstant(ctx, postConst); } adapter.checkWriteBranch(execute, ctx); return null; } void writeConstant(final ParserRuleContext source, final Object constant) { if (constant instanceof Number) { writeNumeric(source, constant); } else if (constant instanceof Character) { writeNumeric(source, (int)(char)constant); } else if (constant instanceof String) { writeString(source, constant); } else if (constant instanceof Boolean) { writeBoolean(source, constant); } else if (constant != null) { throw new IllegalStateException(error(source) + "Unexpected writer state."); } } private void writeNumeric(final ParserRuleContext source, final Object numeric) { if (numeric instanceof Double) { final long bits = Double.doubleToLongBits((Double)numeric); if (bits == 0L) { execute.visitInsn(Opcodes.DCONST_0); } else if (bits == 0x3ff0000000000000L) { execute.visitInsn(Opcodes.DCONST_1); } else { execute.visitLdcInsn(numeric); } } else if (numeric instanceof Float) { final int bits = Float.floatToIntBits((Float)numeric); if (bits == 0L) { execute.visitInsn(Opcodes.FCONST_0); } else if (bits == 0x3f800000) { execute.visitInsn(Opcodes.FCONST_1); } else if (bits == 0x40000000) { execute.visitInsn(Opcodes.FCONST_2); } else { execute.visitLdcInsn(numeric); } } else if (numeric instanceof Long) { final long value = (long)numeric; if (value == 0L) { execute.visitInsn(Opcodes.LCONST_0); } else if (value == 1L) { execute.visitInsn(Opcodes.LCONST_1); } else { execute.visitLdcInsn(value); } } else if (numeric instanceof Number) { final int value = ((Number)numeric).intValue(); if (value == -1) { execute.visitInsn(Opcodes.ICONST_M1); } else if (value == 0) { execute.visitInsn(Opcodes.ICONST_0); } else if (value == 1) { execute.visitInsn(Opcodes.ICONST_1); } else if (value == 2) { execute.visitInsn(Opcodes.ICONST_2); } else if (value == 3) { execute.visitInsn(Opcodes.ICONST_3); } else if (value == 4) { execute.visitInsn(Opcodes.ICONST_4); } else if (value == 5) { execute.visitInsn(Opcodes.ICONST_5); } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { execute.visitIntInsn(Opcodes.BIPUSH, value); } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { execute.visitIntInsn(Opcodes.SIPUSH, value); } else { execute.visitLdcInsn(value); } } else { throw new IllegalStateException(error(source) + "Unexpected writer state."); } } private void writeString(final ParserRuleContext source, final Object string) { if (string instanceof String) { execute.visitLdcInsn(string); } else { throw new IllegalStateException(error(source) + "Unexpected writer state."); } } private void writeBoolean(final ParserRuleContext source, final Object bool) { if (bool instanceof Boolean) { boolean value = (boolean)bool; if (value) { execute.visitInsn(Opcodes.ICONST_1); } else { execute.visitInsn(Opcodes.ICONST_0); } } else { throw new IllegalStateException(error(source) + "Unexpected writer state."); } } void writeNewStrings() { execute.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder"); execute.visitInsn(Opcodes.DUP); execute.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false); } void writeAppendStrings(final ParserRuleContext source, final TypeMetadata metadata) { final String internal = "java/lang/StringBuilder"; final String builder = "Ljava/lang/StringBuilder;"; final String string = "(Ljava/lang/String;)" + builder; final String object = "(Ljava/lang/Object;)" + builder; switch (metadata) { case BOOL: execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, internal, "append", "(Z)" + builder, false); break; case BYTE: execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, internal, "append", "(I)" + builder, false); break; case SHORT: execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, internal, "append", "(I)" + builder, false); break; case CHAR: execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, internal, "append", "(C)" + builder, false); break; case INT: execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, internal, "append", "(I)" + builder, false); break; case LONG: execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, internal, "append", "(J)" + builder, false); break; case FLOAT: execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, internal, "append", "(F)" + builder, false); break; case DOUBLE: execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, internal, "append", "(D)" + builder, false); break; case STRING: execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, internal, "append", string, false); break; case ARRAY: case OBJECT: execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, internal, "append", object, false); break; default: throw new IllegalStateException(error(source) + "Unexpected writer state."); } } void writeToStrings() { execute.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); } void writeBinaryInstruction(final ParserRuleContext source, final TypeMetadata metadata, final int token) { switch (metadata) { case INT: switch (token) { case MUL: execute.visitInsn(Opcodes.IMUL); break; case DIV: execute.visitInsn(Opcodes.IDIV); break; case REM: execute.visitInsn(Opcodes.IREM); break; case ADD: execute.visitInsn(Opcodes.IADD); break; case SUB: execute.visitInsn(Opcodes.ISUB); break; case LSH: execute.visitInsn(Opcodes.ISHL); break; case USH: execute.visitInsn(Opcodes.IUSHR); break; case RSH: execute.visitInsn(Opcodes.ISHR); break; case BWAND: execute.visitInsn(Opcodes.IAND); break; case BWXOR: execute.visitInsn(Opcodes.IXOR); break; case BWOR: execute.visitInsn(Opcodes.IOR); break; default: throw new IllegalStateException(error(source) + "Unexpected writer state."); } break; case LONG: switch (token) { case MUL: execute.visitInsn(Opcodes.LMUL); break; case DIV: execute.visitInsn(Opcodes.LDIV); break; case REM: execute.visitInsn(Opcodes.LREM); break; case ADD: execute.visitInsn(Opcodes.LADD); break; case SUB: execute.visitInsn(Opcodes.LSUB); break; case LSH: execute.visitInsn(Opcodes.LSHL); break; case USH: execute.visitInsn(Opcodes.LUSHR); break; case RSH: execute.visitInsn(Opcodes.LSHR); break; case BWAND: execute.visitInsn(Opcodes.LAND); break; case BWXOR: execute.visitInsn(Opcodes.LXOR); break; case BWOR: execute.visitInsn(Opcodes.LOR); break; default: throw new IllegalStateException(error(source) + "Unexpected writer state."); } break; case FLOAT: switch (token) { case MUL: execute.visitInsn(Opcodes.FMUL); break; case DIV: execute.visitInsn(Opcodes.FDIV); break; case REM: execute.visitInsn(Opcodes.FREM); break; case ADD: execute.visitInsn(Opcodes.FADD); break; case SUB: execute.visitInsn(Opcodes.FSUB); break; default: throw new IllegalStateException(error(source) + "Unexpected writer state."); } break; case DOUBLE: switch (token) { case MUL: execute.visitInsn(Opcodes.DMUL); break; case DIV: execute.visitInsn(Opcodes.DDIV); break; case REM: execute.visitInsn(Opcodes.DREM); break; case ADD: execute.visitInsn(Opcodes.DADD); break; case SUB: execute.visitInsn(Opcodes.DSUB); break; default: throw new IllegalStateException(error(source) + "Unexpected writer state."); } break; default: throw new IllegalStateException(error(source) + "Unexpected writer state."); } } private void writeEnd() { writer.visitEnd(); } private byte[] getBytes() { return writer.toByteArray(); } }