001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.transformer.bytecode.statement; 020 021import java.util.ArrayList; 022import java.util.Iterator; 023import java.util.List; 024 025import lucee.transformer.bytecode.Body; 026import lucee.transformer.bytecode.BytecodeContext; 027import lucee.transformer.bytecode.BytecodeException; 028import lucee.transformer.bytecode.Position; 029import lucee.transformer.bytecode.Statement; 030import lucee.transformer.bytecode.util.ExpressionUtil; 031 032import org.objectweb.asm.Label; 033import org.objectweb.asm.commons.GeneratorAdapter; 034 035public final class NativeSwitch extends StatementBaseNoFinal implements FlowControlBreak,FlowControlContinue,HasBodies { 036 037 public static final short LOCAL_REF=0; 038 public static final short ARG_REF=1; 039 public static final short PRIMITIVE=1; 040 041 042 private int value; 043 private Label end; 044 private Statement defaultCase; 045 List<Case> cases=new ArrayList<Case>(); 046 private Label[] labels=new Label[0]; 047 private int[] values=new int[0]; 048 private short type; 049 050 public NativeSwitch(int value, short type, Position start, Position end) { 051 super(start, end); 052 this.value=value; 053 this.type=type; 054 } 055 056 public void _writeOut(BytecodeContext bc) throws BytecodeException { 057 end = new Label(); 058 GeneratorAdapter adapter = bc.getAdapter(); 059 060 if(type==LOCAL_REF) adapter.loadLocal(value); 061 else if(type==ARG_REF) adapter.loadArg(value); 062 else adapter.push(value); 063 064 Label beforeDefault = new Label(); 065 adapter.visitLookupSwitchInsn(beforeDefault, values, labels); 066 067 Iterator<Case> it = cases.iterator(); 068 Case c; 069 while(it.hasNext()) { 070 c= it.next(); 071 adapter.visitLabel(c.label); 072 ExpressionUtil.visitLine(bc, c.startPos); 073 c.body.writeOut(bc); 074 ExpressionUtil.visitLine(bc, c.endPos); 075 if(c.doBreak){ 076 adapter.goTo(end); 077 } 078 } 079 080 081 adapter.visitLabel(beforeDefault); 082 if(defaultCase!=null)defaultCase.writeOut(bc); 083 adapter.visitLabel(end); 084 085 } 086 087 public void addCase(int value, Statement body,Position start,Position end,boolean doBreak) { 088 089 Case nc = new Case(value,body,start,end,doBreak); 090 091 Label[] labelsTmp = new Label[cases.size()+1]; 092 int[] valuesTmp = new int[cases.size()+1]; 093 094 int count=0; 095 boolean hasAdd=false; 096 for(int i=0;i<labels.length;i++) { 097 if(!hasAdd && nc.value<values[i]) { 098 labelsTmp[count]=nc.label; 099 valuesTmp[count]=nc.value; 100 count++; 101 hasAdd=true; 102 } 103 labelsTmp[count]=labels[i]; 104 valuesTmp[count]=values[i]; 105 count++; 106 } 107 if(!hasAdd) { 108 labelsTmp[labels.length]=nc.label; 109 valuesTmp[values.length]=nc.value; 110 } 111 labels=labelsTmp; 112 values=valuesTmp; 113 114 115 cases.add(nc); 116 } 117 118 public void addDefaultCase(Statement defaultStatement) { 119 this.defaultCase=defaultStatement; 120 } 121 122 class Case { 123 124 public boolean doBreak; 125 private int value; 126 private Statement body; 127 private Label label=new Label(); 128 private Position startPos; 129 private Position endPos; 130 131 public Case(int value, Statement body,Position startline,Position endline, boolean doBreak) { 132 this.value=value; 133 this.body=body; 134 this.startPos=startline; 135 this.endPos=endline; 136 this.doBreak=doBreak; 137 } 138 139 } 140 141 /** 142 * 143 * @see lucee.transformer.bytecode.statement.FlowControl#getBreakLabel() 144 */ 145 public Label getBreakLabel() { 146 return end; 147 } 148 149 /** 150 * 151 * @see lucee.transformer.bytecode.statement.FlowControl#getContinueLabel() 152 */ 153 public Label getContinueLabel() { 154 return end; 155 } 156 157 /** 158 * @see lucee.transformer.bytecode.statement.HasBodies#getBodies() 159 */ 160 public Body[] getBodies() { 161 if(cases==null) { 162 if(defaultCase!=null) return new Body[]{(Body) defaultCase}; 163 return new Body[]{}; 164 } 165 166 int len=cases.size(),count=0; 167 if(defaultCase!=null)len++; 168 Body[] bodies=new Body[len]; 169 Case c; 170 Iterator<Case> it = cases.iterator(); 171 while(it.hasNext()) { 172 c=it.next(); 173 bodies[count++]=(Body) c.body; 174 } 175 if(defaultCase!=null)bodies[count++]=(Body) defaultCase; 176 177 return bodies; 178 } 179 180 @Override 181 public String getLabel() { 182 return null; 183 } 184}