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.util; 020 021import java.io.IOException; 022import java.lang.reflect.Field; 023import java.util.ArrayList; 024import java.util.Iterator; 025import java.util.List; 026 027import lucee.aprint; 028import lucee.commons.digest.MD5; 029import lucee.commons.io.IOUtil; 030import lucee.commons.io.res.Resource; 031import lucee.commons.lang.ExceptionUtil; 032import lucee.commons.lang.StringUtil; 033import lucee.runtime.component.Property; 034import lucee.runtime.config.Config; 035import lucee.runtime.exp.PageException; 036import lucee.runtime.net.rpc.AxisCaster; 037import lucee.runtime.op.Caster; 038import lucee.runtime.op.Decision; 039import lucee.runtime.type.dt.TimeSpanImpl; 040import lucee.runtime.type.util.ArrayUtil; 041import lucee.runtime.type.util.ListUtil; 042import lucee.transformer.bytecode.Body; 043import lucee.transformer.bytecode.BytecodeContext; 044import lucee.transformer.bytecode.BytecodeException; 045import lucee.transformer.bytecode.Literal; 046import lucee.transformer.bytecode.Page; 047import lucee.transformer.bytecode.Position; 048import lucee.transformer.bytecode.ScriptBody; 049import lucee.transformer.bytecode.Statement; 050import lucee.transformer.bytecode.cast.Cast; 051import lucee.transformer.bytecode.cast.CastBoolean; 052import lucee.transformer.bytecode.cast.CastDouble; 053import lucee.transformer.bytecode.cast.CastString; 054import lucee.transformer.bytecode.expression.ExprDouble; 055import lucee.transformer.bytecode.expression.ExprString; 056import lucee.transformer.bytecode.expression.Expression; 057import lucee.transformer.bytecode.expression.var.Argument; 058import lucee.transformer.bytecode.expression.var.BIF; 059import lucee.transformer.bytecode.expression.var.DataMember; 060import lucee.transformer.bytecode.expression.var.Member; 061import lucee.transformer.bytecode.expression.var.NullExpression; 062import lucee.transformer.bytecode.expression.var.Variable; 063import lucee.transformer.bytecode.expression.var.VariableString; 064import lucee.transformer.bytecode.literal.Identifier; 065import lucee.transformer.bytecode.literal.LitBoolean; 066import lucee.transformer.bytecode.literal.LitDouble; 067import lucee.transformer.bytecode.literal.LitLong; 068import lucee.transformer.bytecode.literal.LitString; 069import lucee.transformer.bytecode.statement.FlowControl; 070import lucee.transformer.bytecode.statement.FlowControlBreak; 071import lucee.transformer.bytecode.statement.FlowControlContinue; 072import lucee.transformer.bytecode.statement.FlowControlFinal; 073import lucee.transformer.bytecode.statement.FlowControlRetry; 074import lucee.transformer.bytecode.statement.HasBody; 075import lucee.transformer.bytecode.statement.PrintOut; 076import lucee.transformer.bytecode.statement.Switch; 077import lucee.transformer.bytecode.statement.TryCatchFinally; 078import lucee.transformer.bytecode.statement.tag.Attribute; 079import lucee.transformer.bytecode.statement.tag.Tag; 080import lucee.transformer.bytecode.statement.tag.TagComponent; 081import lucee.transformer.bytecode.statement.tag.TagTry; 082import lucee.transformer.bytecode.util.SourceNameClassVisitor.SourceInfo; 083import lucee.transformer.cfml.evaluator.EvaluatorException; 084 085import org.objectweb.asm.ClassReader; 086import org.objectweb.asm.ClassWriter; 087import org.objectweb.asm.FieldVisitor; 088import org.objectweb.asm.Label; 089import org.objectweb.asm.MethodVisitor; 090import org.objectweb.asm.Opcodes; 091import org.objectweb.asm.Type; 092import org.objectweb.asm.commons.GeneratorAdapter; 093import org.objectweb.asm.commons.Method; 094 095public final class ASMUtil { 096 097 //private static final int VERSION_2=1; 098 //private static final int VERSION_3=2; 099 100 public static final short TYPE_ALL=0; 101 public static final short TYPE_BOOLEAN=1; 102 public static final short TYPE_NUMERIC=2; 103 public static final short TYPE_STRING=4; 104 105 106 107 108 //private static int version=0; 109 110 private final static Method CONSTRUCTOR_OBJECT = Method.getMethod("void <init> ()"); 111 private static final Method _SRC_NAME = new Method("_srcName", 112 Types.STRING, 113 new Type[]{} 114 ); 115 //private static final String VERSION_MESSAGE = "you use an invalid version of the ASM Jar, please update your jar files"; 116 private static long id=0; 117 118 /** 119 * Gibt zurueck ob das direkt uebergeordnete Tag mit dem uebergebenen Full-Name (Namespace und Name) existiert. 120 * @param el Startelement, von wo aus gesucht werden soll. 121 * @param fullName Name des gesuchten Tags. 122 * @return Existiert ein solches Tag oder nicht. 123 */ 124 public static boolean hasAncestorTag(Tag tag, String fullName) { 125 return getAncestorTag(tag, fullName)!=null; 126 } 127 128 129 /** 130 * Gibt das uebergeordnete CFXD Tag Element zurueck, falls dies nicht existiert wird null zurueckgegeben. 131 * @param el Element von dem das parent Element zurueckgegeben werden soll. 132 * @return uebergeordnete CFXD Tag Element 133 */ 134 public static Tag getParentTag(Tag tag) { 135 Statement p=tag.getParent(); 136 if(p==null)return null; 137 p=p.getParent(); 138 if(p instanceof Tag) return (Tag) p; 139 return null; 140 } 141 142 public static boolean isParentTag(Tag tag,String fullName) { 143 Tag p = getParentTag(tag); 144 if(p==null) return false; 145 return p.getFullname().equalsIgnoreCase(fullName); 146 147 } 148 public static boolean isParentTag(Tag tag,Class clazz) { 149 Tag p = getParentTag(tag); 150 if(p==null) return false; 151 return p.getClass()==clazz; 152 153 } 154 155 public static boolean hasAncestorRetryFCStatement(Statement stat,String label) { 156 return getAncestorRetryFCStatement(stat,null,label)!=null; 157 } 158 159 public static boolean hasAncestorBreakFCStatement(Statement stat,String label) { 160 return getAncestorBreakFCStatement(stat,null,label)!=null; 161 } 162 163 public static boolean hasAncestorContinueFCStatement(Statement stat,String label) { 164 return getAncestorContinueFCStatement(stat,null,label)!=null; 165 } 166 167 168 169 public static FlowControlRetry getAncestorRetryFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) { 170 return (FlowControlRetry) getAncestorFCStatement(stat, finallyLabels, FlowControl.RETRY,label); 171 } 172 public static FlowControlBreak getAncestorBreakFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) { 173 return (FlowControlBreak) getAncestorFCStatement(stat, finallyLabels, FlowControl.BREAK,label); 174 } 175 176 public static FlowControlContinue getAncestorContinueFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) { 177 return (FlowControlContinue) getAncestorFCStatement(stat, finallyLabels, FlowControl.CONTINUE,label); 178 } 179 180 private static FlowControl getAncestorFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, int flowType, String label) { 181 Statement parent = stat; 182 FlowControlFinal fcf; 183 while(true) { 184 parent=parent.getParent(); 185 if(parent==null)return null; 186 if( 187 ((flowType==FlowControl.RETRY && parent instanceof FlowControlRetry) || 188 (flowType==FlowControl.CONTINUE && parent instanceof FlowControlContinue) || 189 (flowType==FlowControl.BREAK && parent instanceof FlowControlBreak)) 190 && 191 labelMatch((FlowControl)parent,label)) { 192 if(parent instanceof ScriptBody){ 193 List<FlowControlFinal> _finallyLabels=finallyLabels==null?null:new ArrayList<FlowControlFinal>(); 194 195 FlowControl scriptBodyParent = getAncestorFCStatement(parent,_finallyLabels,flowType,label); 196 if(scriptBodyParent!=null) { 197 if(finallyLabels!=null){ 198 Iterator<FlowControlFinal> it = _finallyLabels.iterator(); 199 while(it.hasNext()){ 200 finallyLabels.add(it.next()); 201 } 202 } 203 return scriptBodyParent; 204 } 205 return (FlowControl)parent; 206 } 207 return (FlowControl) parent; 208 } 209 210 // only if not last 211 if(finallyLabels!=null){ 212 fcf = parent.getFlowControlFinal(); 213 if(fcf!=null){ 214 finallyLabels.add(fcf); 215 } 216 } 217 218 } 219 } 220 221 private static boolean labelMatch(FlowControl fc, String label) { 222 if(StringUtil.isEmpty(label,true)) return true; 223 String fcl = fc.getLabel(); 224 if(StringUtil.isEmpty(fcl,true)) return false; 225 226 return label.trim().equalsIgnoreCase(fcl.trim()); 227 } 228 229 230 public static void leadFlow(BytecodeContext bc,Statement stat, int flowType, String label) throws BytecodeException { 231 List<FlowControlFinal> finallyLabels=new ArrayList<FlowControlFinal>(); 232 233 FlowControl fc; 234 String name; 235 if(FlowControl.BREAK==flowType) { 236 fc=ASMUtil.getAncestorBreakFCStatement(stat,finallyLabels,label); 237 name="break"; 238 } 239 else if(FlowControl.CONTINUE==flowType) { 240 fc=ASMUtil.getAncestorContinueFCStatement(stat,finallyLabels,label); 241 name="continue"; 242 } 243 else { 244 fc=ASMUtil.getAncestorRetryFCStatement(stat,finallyLabels,label); 245 name="retry"; 246 } 247 248 if(fc==null) 249 throw new BytecodeException(name+" must be inside a loop (for,while,do-while,<cfloop>,<cfwhile> ...)",stat.getStart()); 250 251 GeneratorAdapter adapter = bc.getAdapter(); 252 253 Label end; 254 if(FlowControl.BREAK==flowType) end=((FlowControlBreak)fc).getBreakLabel(); 255 else if(FlowControl.CONTINUE==flowType) end=((FlowControlContinue)fc).getContinueLabel(); 256 else end=((FlowControlRetry)fc).getRetryLabel(); 257 258 // first jump to all final labels 259 FlowControlFinal[] arr = finallyLabels.toArray(new FlowControlFinal[finallyLabels.size()]); 260 if(arr.length>0) { 261 FlowControlFinal fcf; 262 for(int i=0;i<arr.length;i++){ 263 fcf=arr[i]; 264 265 // first 266 if(i==0) { 267 adapter.visitJumpInsn(Opcodes.GOTO, fcf.getFinalEntryLabel()); 268 } 269 270 // last 271 if(arr.length==i+1) fcf.setAfterFinalGOTOLabel(end); 272 else fcf.setAfterFinalGOTOLabel(arr[i+1].getFinalEntryLabel()); 273 } 274 275 } 276 else bc.getAdapter().visitJumpInsn(Opcodes.GOTO, end); 277 } 278 279 280 281 public static boolean hasAncestorTryStatement(Statement stat) { 282 return getAncestorTryStatement(stat)!=null; 283 } 284 285 public static Statement getAncestorTryStatement(Statement stat) { 286 Statement parent = stat; 287 while(true) { 288 parent=parent.getParent(); 289 if(parent==null)return null; 290 291 if(parent instanceof TagTry) { 292 return parent; 293 } 294 else if(parent instanceof TryCatchFinally) { 295 return parent; 296 } 297 } 298 } 299 300 301 302 303 /** 304 * Gibt ein uebergeordnetes Tag mit dem uebergebenen Full-Name (Namespace und Name) zurueck, 305 * falls ein solches existiert, andernfalls wird null zurueckgegeben. 306 * @param el Startelement, von wo aus gesucht werden soll. 307 * @param fullName Name des gesuchten Tags. 308 * @return uebergeornetes Element oder null. 309 */ 310 public static Tag getAncestorTag(Tag tag, String fullName) { 311 Statement parent=tag; 312 while(true) { 313 parent=parent.getParent(); 314 if(parent==null)return null; 315 if(parent instanceof Tag) { 316 tag=(Tag) parent; 317 if(tag.getFullname().equalsIgnoreCase(fullName)) 318 return tag; 319 } 320 } 321 } 322 323 324 325 /** 326 * extract the content of a attribut 327 * @param cfxdTag 328 * @param attrName 329 * @return attribute value 330 * @throws EvaluatorException 331 */ 332 public static Boolean getAttributeBoolean(Tag tag,String attrName) throws EvaluatorException { 333 Boolean b= getAttributeLiteral(tag, attrName).getBoolean(null); 334 if(b==null)throw new EvaluatorException("attribute ["+attrName+"] must be a constant boolean value"); 335 return b; 336 } 337 338 /** 339 * extract the content of a attribut 340 * @param cfxdTag 341 * @param attrName 342 * @return attribute value 343 * @throws EvaluatorException 344 */ 345 public static Boolean getAttributeBoolean(Tag tag,String attrName, Boolean defaultValue) { 346 Literal lit=getAttributeLiteral(tag, attrName,null); 347 if(lit==null) return defaultValue; 348 return lit.getBoolean(defaultValue); 349 } 350 351 352 /** 353 * extract the content of a attribut 354 * @param cfxdTag 355 * @param attrName 356 * @return attribute value 357 * @throws EvaluatorException 358 */ 359 public static String getAttributeString(Tag tag,String attrName) throws EvaluatorException { 360 return getAttributeLiteral(tag, attrName).getString(); 361 } 362 363 /** 364 * extract the content of a attribut 365 * @param cfxdTag 366 * @param attrName 367 * @return attribute value 368 * @throws EvaluatorException 369 */ 370 public static String getAttributeString(Tag tag,String attrName, String defaultValue) { 371 Literal lit=getAttributeLiteral(tag, attrName,null); 372 if(lit==null) return defaultValue; 373 return lit.getString(); 374 } 375 376 /** 377 * extract the content of a attribut 378 * @param cfxdTag 379 * @param attrName 380 * @return attribute value 381 * @throws EvaluatorException 382 */ 383 public static Literal getAttributeLiteral(Tag tag,String attrName) throws EvaluatorException { 384 Attribute attr = tag.getAttribute(attrName); 385 if(attr!=null && attr.getValue() instanceof Literal) return ((Literal)attr.getValue()); 386 throw new EvaluatorException("attribute ["+attrName+"] must be a constant value"); 387 } 388 389 390 391 /** 392 * extract the content of a attribut 393 * @param cfxdTag 394 * @param attrName 395 * @return attribute value 396 * @throws EvaluatorException 397 */ 398 public static Literal getAttributeLiteral(Tag tag,String attrName, Literal defaultValue) { 399 Attribute attr = tag.getAttribute(attrName); 400 if(attr!=null && attr.getValue() instanceof Literal) return ((Literal)attr.getValue()); 401 return defaultValue; 402 } 403 404 405 406 407 /** 408 * Prueft ob das das angegebene Tag in der gleichen Ebene nach dem angegebenen Tag vorkommt. 409 * @param tag Ausgangspunkt, nach diesem tag darf das angegebene nicht vorkommen. 410 * @param nameToFind Tag Name der nicht vorkommen darf 411 * @return kommt das Tag vor. 412 */ 413 public static boolean hasSisterTagAfter(Tag tag, String nameToFind) { 414 Body body=(Body) tag.getParent(); 415 List<Statement> stats = body.getStatements(); 416 Iterator<Statement> it = stats.iterator(); 417 Statement other; 418 419 boolean isAfter=false; 420 while(it.hasNext()) { 421 other=it.next(); 422 423 if(other instanceof Tag) { 424 if(isAfter) { 425 if(((Tag) other).getTagLibTag().getName().equals(nameToFind)) 426 return true; 427 } 428 else if(other == tag) isAfter=true; 429 } 430 } 431 return false; 432 } 433 434 /** 435 * Prueft ob das angegebene Tag innerhalb seiner Ebene einmalig ist oder nicht. 436 * @param tag Ausgangspunkt, nach diesem tag darf das angegebene nicht vorkommen. 437 * @return kommt das Tag vor. 438 */ 439 public static boolean hasSisterTagWithSameName(Tag tag) { 440 441 Body body=(Body) tag.getParent(); 442 List<Statement> stats = body.getStatements(); 443 Iterator<Statement> it = stats.iterator(); 444 Statement other; 445 String name=tag.getTagLibTag().getName(); 446 447 while(it.hasNext()) { 448 other=it.next(); 449 if(other != tag && other instanceof Tag && ((Tag) other).getTagLibTag().getName().equals(name)) 450 return true; 451 452 } 453 return false; 454 } 455 456 /** 457 * remove this tag from his parent body 458 * @param tag 459 */ 460 public static void remove(Tag tag) { 461 Body body=(Body) tag.getParent(); 462 body.getStatements().remove(tag); 463 } 464 465 /** 466 * replace src with trg 467 * @param src 468 * @param trg 469 */ 470 public static void replace(Tag src, Tag trg, boolean moveBody) { 471 trg.setParent(src.getParent()); 472 473 Body p=(Body) src.getParent(); 474 List<Statement> stats = p.getStatements(); 475 Iterator<Statement> it = stats.iterator(); 476 Statement stat; 477 int count=0; 478 479 while(it.hasNext()) { 480 stat=it.next(); 481 if(stat==src) { 482 if(moveBody && src.getBody()!=null)src.getBody().setParent(trg); 483 stats.set(count, trg); 484 break; 485 } 486 count++; 487 } 488 } 489 490 public static Page getAncestorPage(Statement stat) throws BytecodeException { 491 Statement parent=stat; 492 while(true) { 493 parent=parent.getParent(); 494 if(parent==null) { 495 throw new BytecodeException("missing parent Statement of Statement",stat.getStart()); 496 //return null; 497 } 498 if(parent instanceof Page) return (Page) parent; 499 } 500 } 501 502 public static Page getAncestorPage(Statement stat, Page defaultValue) { 503 Statement parent=stat; 504 while(true) { 505 parent=parent.getParent(); 506 if(parent==null) { 507 return defaultValue; 508 } 509 if(parent instanceof Page) return (Page) parent; 510 } 511 } 512 513 public static void listAncestor(Statement stat) { 514 Statement parent=stat; 515 aprint.o(stat); 516 while(true) { 517 parent=parent.getParent(); 518 if(parent instanceof Page)aprint.o("page-> "+ ((Page)parent).getPageSource().getDisplayPath()); 519 else aprint.o("parent-> "+ parent); 520 if(parent==null) break; 521 } 522 } 523 524 525 public static Tag getAncestorComponent(Statement stat) throws BytecodeException { 526 //print.ln("getAncestorPage:"+stat); 527 Statement parent=stat; 528 while(true) { 529 parent=parent.getParent(); 530 //print.ln(" - "+parent); 531 if(parent==null) { 532 throw new BytecodeException("missing parent Statement of Statement",stat.getStart()); 533 //return null; 534 } 535 if(parent instanceof TagComponent) 536 //if(parent instanceof Tag && "component".equals(((Tag)parent).getTagLibTag().getName())) 537 return (Tag) parent; 538 } 539 } 540 541 public static Statement getRoot(Statement stat) { 542 while(true) { 543 if(isRoot(stat)) { 544 return stat; 545 } 546 stat=stat.getParent(); 547 } 548 } 549 550 551 552 public static boolean isRoot(Statement statement) { 553 //return statement instanceof Page || (statement instanceof Tag && "component".equals(((Tag)statement).getTagLibTag().getName())); 554 return statement instanceof Page || statement instanceof TagComponent; 555 } 556 557 public static void invokeMethod(GeneratorAdapter adapter, Type type, Method method) { 558 if(type.getClass().isInterface()) 559 adapter.invokeInterface(type, method); 560 else 561 adapter.invokeVirtual(type, method); 562 } 563 564 public static byte[] createPojo(String className, ASMProperty[] properties,Class parent,Class[] interfaces, String srcName) throws PageException { 565 className=className.replace('.', '/'); 566 className=className.replace('\\', '/'); 567 className=ListUtil.trim(className, "/"); 568 String[] inter=null; 569 if(interfaces!=null){ 570 inter=new String[interfaces.length]; 571 for(int i=0;i<inter.length;i++){ 572 inter[i]=interfaces[i].getName().replace('.', '/'); 573 } 574 } 575 // CREATE CLASS 576 ClassWriter cw = ASMUtil.getClassWriter(); 577 cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, className, null, parent.getName().replace('.', '/'), inter); 578 String md5; 579 try{ 580 md5=createMD5(properties); 581 } 582 catch(Throwable t){ 583 ExceptionUtil.rethrowIfNecessary(t); 584 md5=""; 585 t.printStackTrace(); 586 } 587 588 FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "_md5_", "Ljava/lang/String;", null, md5); 589 fv.visitEnd(); 590 591 592 // Constructor 593 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR_OBJECT,null,null,cw); 594 adapter.loadThis(); 595 adapter.invokeConstructor(toType(parent,true), CONSTRUCTOR_OBJECT); 596 adapter.returnValue(); 597 adapter.endMethod(); 598 599 // properties 600 for(int i=0;i<properties.length;i++){ 601 createProperty(cw,className,properties[i]); 602 } 603 604 // complexType src 605 if(!StringUtil.isEmpty(srcName)) { 606 GeneratorAdapter _adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+ Opcodes.ACC_STATIC , _SRC_NAME, null, null, cw); 607 _adapter.push(srcName); 608 _adapter.returnValue(); 609 _adapter.endMethod(); 610 } 611 612 cw.visitEnd(); 613 return cw.toByteArray(); 614 } 615 616 private static void createProperty(ClassWriter cw,String classType, ASMProperty property) throws PageException { 617 String name = property.getName(); 618 Type type = property.getASMType(); 619 Class clazz = property.getClazz(); 620 621 cw.visitField(Opcodes.ACC_PRIVATE, name, type.toString(), null, null).visitEnd(); 622 623 int load=loadFor(type); 624 //int sizeOf=sizeOf(type); 625 626 // get<PropertyName>():<type> 627 Type[] types=new Type[0]; 628 Method method = new Method((clazz==boolean.class?"get":"get")+(name),type,types); 629 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , method, null, null, cw); 630 631 Label start = new Label(); 632 adapter.visitLabel(start); 633 634 adapter.visitVarInsn(Opcodes.ALOAD, 0); 635 adapter.visitFieldInsn(Opcodes.GETFIELD, classType, name, type.toString()); 636 adapter.returnValue(); 637 638 Label end = new Label(); 639 adapter.visitLabel(end); 640 adapter.visitLocalVariable("this", "L"+classType+";", null, start, end, 0); 641 adapter.visitEnd(); 642 643 adapter.endMethod(); 644 645 646 647 648 649 // set<PropertyName>(object):void 650 types=new Type[]{type}; 651 method = new Method("set"+(name),Types.VOID,types); 652 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , method, null, null, cw); 653 654 start = new Label(); 655 adapter.visitLabel(start); 656 adapter.visitVarInsn(Opcodes.ALOAD, 0); 657 adapter.visitVarInsn(load, 1); 658 adapter.visitFieldInsn(Opcodes.PUTFIELD, classType, name, type.toString()); 659 660 adapter.visitInsn(Opcodes.RETURN); 661 end = new Label(); 662 adapter.visitLabel(end); 663 adapter.visitLocalVariable("this", "L"+classType+";", null, start, end, 0); 664 adapter.visitLocalVariable(name, type.toString(), null, start, end, 1); 665 //adapter.visitMaxs(0, 0);//.visitMaxs(sizeOf+1, sizeOf+1);// hansx 666 adapter.visitEnd(); 667 668 adapter.endMethod(); 669 670 671 672 673 } 674 675 public static int loadFor(Type type) { 676 if(type.equals(Types.BOOLEAN_VALUE) || type.equals(Types.INT_VALUE) || type.equals(Types.CHAR) || type.equals(Types.SHORT_VALUE)) 677 return Opcodes.ILOAD; 678 if(type.equals(Types.FLOAT_VALUE)) 679 return Opcodes.FLOAD; 680 if(type.equals(Types.LONG_VALUE)) 681 return Opcodes.LLOAD; 682 if(type.equals(Types.DOUBLE_VALUE)) 683 return Opcodes.DLOAD; 684 return Opcodes.ALOAD; 685 } 686 687 public static int sizeOf(Type type) { 688 if(type.equals(Types.LONG_VALUE) || type.equals(Types.DOUBLE_VALUE)) 689 return 2; 690 return 1; 691 } 692 693 694 /** 695 * translate a string cfml type definition to a Type Object 696 * @param cfType 697 * @param axistype 698 * @return 699 * @throws PageException 700 */ 701 public static Type toType(String cfType, boolean axistype) throws PageException { 702 return toType(Caster.cfTypeToClass(cfType), axistype); 703 } 704 705 /** 706 * translate a string cfml type definition to a Type Object 707 * @param cfType 708 * @param axistype 709 * @return 710 * @throws PageException 711 */ 712 public static Type toType(Class type, boolean axistype) { 713 if(axistype)type=AxisCaster.toAxisTypeClass(type); 714 return Type.getType(type); 715 } 716 717 718 public static String createMD5(ASMProperty[] props) { 719 720 StringBuffer sb=new StringBuffer(); 721 for(int i=0;i<props.length;i++){ 722 sb.append("name:"+props[i].getName()+";"); 723 if(props[i] instanceof Property){ 724 sb.append("type:"+((Property)props[i]).getType()+";"); 725 } 726 else { 727 try { 728 sb.append("type:"+props[i].getASMType()+";"); 729 730 } 731 catch (PageException e) {} 732 } 733 } 734 try { 735 return MD5.getDigestAsString(sb.toString()); 736 } catch (IOException e) { 737 return ""; 738 } 739 } 740 741 742 743 public static void removeLiterlChildren(Tag tag, boolean recursive) { 744 Body body=tag.getBody(); 745 if(body!=null) { 746 List<Statement> list = body.getStatements(); 747 Statement[] stats = list.toArray(new Statement[list.size()]); 748 PrintOut po; 749 Tag t; 750 for(int i=0;i<stats.length;i++) { 751 if(stats[i] instanceof PrintOut) { 752 po=(PrintOut) stats[i]; 753 if(po.getExpr() instanceof Literal) { 754 body.getStatements().remove(po); 755 } 756 } 757 else if(recursive && stats[i] instanceof Tag) { 758 t=(Tag) stats[i]; 759 if(t.getTagLibTag().isAllowRemovingLiteral()) { 760 removeLiterlChildren(t, recursive); 761 } 762 } 763 } 764 } 765 } 766 767 768 public synchronized static String getId() { 769 if(id<0)id=0; 770 return StringUtil.addZeros(++id,6); 771 } 772 773 774 public static boolean isEmpty(Body body) { 775 return body==null || body.isEmpty(); 776 } 777 778 779 /** 780 * @param adapter 781 * @param expr 782 * @param mode 783 */ 784 public static void pop(GeneratorAdapter adapter, Expression expr,int mode) { 785 if(mode==Expression.MODE_VALUE && (expr instanceof ExprDouble))adapter.pop2(); 786 else adapter.pop(); 787 } 788 public static void pop(GeneratorAdapter adapter, Type type) { 789 if(type.equals(Types.DOUBLE_VALUE))adapter.pop2(); 790 else if(type.equals(Types.VOID)); 791 else adapter.pop(); 792 } 793 794 795 public static ClassWriter getClassWriter() { 796 return new ClassWriter(ClassWriter.COMPUTE_MAXS);//|ClassWriter.COMPUTE_FRAMES); 797 798 } 799 800 801 public static String createOverfowMethod(String prefix, int id) { // pattern is used in function callstackget 802 if(StringUtil.isEmpty(prefix)) prefix="call"; 803 return prefix+"_"+StringUtil.addZeros(id,6); 804 } 805 806 public static boolean isOverfowMethod(String name) { 807 return name.length()>6 && Decision.isNumeric(name.substring(name.length()-6,name.length())); 808 //return name.startsWith("_call") && name.length()>=11; 809 } 810 811 812 public static boolean isDotKey(ExprString expr) { 813 return expr instanceof LitString && !((LitString)expr).fromBracket(); 814 } 815 816 public static String toString(Expression exp,String defaultValue) { 817 try { 818 return toString(exp); 819 } catch (BytecodeException e) { 820 return defaultValue; 821 } 822 } 823 public static String toString(Expression exp) throws BytecodeException { 824 if(exp instanceof Variable) { 825 return toString(VariableString.toExprString(exp)); 826 } 827 else if(exp instanceof VariableString) { 828 return ((VariableString)exp).castToString(); 829 } 830 else if(exp instanceof Literal) { 831 return ((Literal)exp).toString(); 832 } 833 return null; 834 } 835 836 837 public static Boolean toBoolean(Attribute attr, Position start) throws BytecodeException { 838 if(attr==null) 839 throw new BytecodeException("attribute does not exist",start); 840 841 if(attr.getValue() instanceof Literal){ 842 Boolean b=((Literal)attr.getValue()).getBoolean(null); 843 if(b!=null) return b; 844 } 845 throw new BytecodeException("attribute ["+attr.getName()+"] must be a constant boolean value",start); 846 847 848 } 849 public static Boolean toBoolean(Attribute attr, int line, Boolean defaultValue) { 850 if(attr==null) 851 return defaultValue; 852 853 if(attr.getValue() instanceof Literal){ 854 Boolean b=((Literal)attr.getValue()).getBoolean(null); 855 if(b!=null) return b; 856 } 857 return defaultValue; 858 } 859 860 861 public static boolean isCFC(Statement s) { 862 Statement p; 863 while((p=s.getParent())!=null){ 864 s=p; 865 } 866 867 return true; 868 } 869 870 public static boolean isLiteralAttribute(Tag tag, String attrName, short type,boolean required,boolean throwWhenNot) throws EvaluatorException { 871 return isLiteralAttribute(tag,tag.getAttribute(attrName), type, required, throwWhenNot); 872 } 873 874 875 public static boolean isLiteralAttribute(Tag tag,Attribute attr, short type,boolean required,boolean throwWhenNot) throws EvaluatorException { 876 String strType="/constant"; 877 if(attr!=null && !isNull(attr.getValue())) { 878 879 switch(type){ 880 case TYPE_ALL: 881 if(attr.getValue() instanceof Literal) return true; 882 break; 883 case TYPE_BOOLEAN: 884 if(CastBoolean.toExprBoolean(attr.getValue()) instanceof LitBoolean) return true; 885 strType=" boolean"; 886 break; 887 case TYPE_NUMERIC: 888 if(CastDouble.toExprDouble(attr.getValue()) instanceof LitDouble) return true; 889 strType=" numeric"; 890 break; 891 case TYPE_STRING: 892 if(CastString.toExprString(attr.getValue()) instanceof LitString) return true; 893 strType=" string"; 894 break; 895 } 896 if(!throwWhenNot) return false; 897 throw new EvaluatorException("Attribute ["+attr.getName()+"] of the Tag ["+tag.getFullname()+"] must be a literal"+strType+" value. "+ 898 "attributes java class type "+attr.getValue().getClass().getName()); 899 } 900 if(required){ 901 if(!throwWhenNot) return false; 902 throw new EvaluatorException("Attribute ["+attr.getName()+"] of the Tag ["+tag.getFullname()+"] is required"); 903 } 904 return false; 905 } 906 907 908 public static boolean isNull(Expression expr) { 909 if(expr instanceof NullExpression) return true; 910 if(expr instanceof Cast) { 911 return isNull(((Cast)expr).getExpr()); 912 } 913 return false; 914 } 915 916 917 public static boolean isRefType(Type type) { 918 return 919 !(type==Types.BYTE_VALUE || type==Types.BOOLEAN_VALUE || type==Types.CHAR || type==Types.DOUBLE_VALUE || 920 type==Types.FLOAT_VALUE || type==Types.INT_VALUE || type==Types.LONG_VALUE || type==Types.SHORT_VALUE); 921 } 922 923 924 public static Type toRefType(Type type) { 925 if(type==Types.BYTE_VALUE) return Types.BYTE; 926 if(type==Types.BOOLEAN_VALUE) return Types.BOOLEAN; 927 if(type==Types.CHAR) return Types.CHARACTER; 928 if(type==Types.DOUBLE_VALUE) return Types.DOUBLE; 929 if(type==Types.FLOAT_VALUE) return Types.FLOAT; 930 if(type==Types.INT_VALUE) return Types.INTEGER; 931 if(type==Types.LONG_VALUE) return Types.LONG; 932 if(type==Types.SHORT_VALUE) return Types.SHORT; 933 934 return type; 935 } 936 937 /** 938 * return value type only when there is one 939 * @param type 940 * @return 941 */ 942 public static Type toValueType(Type type) { 943 if(type==Types.BYTE) return Types.BYTE_VALUE; 944 if(type==Types.BOOLEAN) return Types.BOOLEAN_VALUE; 945 if(type==Types.CHARACTER) return Types.CHAR; 946 if(type==Types.DOUBLE) return Types.DOUBLE_VALUE; 947 if(type==Types.FLOAT) return Types.FLOAT_VALUE; 948 if(type==Types.INTEGER) return Types.INT_VALUE; 949 if(type==Types.LONG) return Types.LONG_VALUE; 950 if(type==Types.SHORT) return Types.SHORT_VALUE; 951 952 return type; 953 } 954 955 956 public static Class getValueTypeClass(Type type, Class defaultValue) { 957 958 if(type==Types.BYTE_VALUE) return byte.class; 959 if(type==Types.BOOLEAN_VALUE) return boolean.class; 960 if(type==Types.CHAR) return char.class; 961 if(type==Types.DOUBLE_VALUE) return double.class; 962 if(type==Types.FLOAT_VALUE) return float.class; 963 if(type==Types.INT_VALUE) return int.class; 964 if(type==Types.LONG_VALUE) return long.class; 965 if(type==Types.SHORT_VALUE) return short.class; 966 967 return defaultValue; 968 } 969 970 public static ASMProperty[] toASMProperties(Property[] properties) { 971 ASMProperty[] asmp=new ASMProperty[properties.length]; 972 for(int i=0;i<asmp.length;i++){ 973 asmp[i]=(ASMProperty) properties[i]; 974 } 975 return asmp; 976 } 977 978 979 public static boolean containsComponent(Body body) { 980 if(body==null) return false; 981 982 Iterator<Statement> it = body.getStatements().iterator(); 983 while(it.hasNext()){ 984 if(it.next() instanceof TagComponent)return true; 985 } 986 return false; 987 } 988 989 990 public static void dummy1(BytecodeContext bc) { 991 bc.getAdapter().visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J"); 992 bc.getAdapter().visitInsn(Opcodes.POP2); 993 } 994 public static void dummy2(BytecodeContext bc) { 995 bc.getAdapter().visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "nanoTime", "()J"); 996 bc.getAdapter().visitInsn(Opcodes.POP2); 997 } 998 999 1000 /** 1001 * convert a clas array to a type array 1002 * @param classes 1003 * @return 1004 */ 1005 public static Type[] toTypes(Class<?>[] classes) { 1006 if(classes==null || classes.length==0) 1007 return new Type[0]; 1008 1009 Type[] types=new Type[classes.length]; 1010 for(int i=0;i<classes.length;i++) { 1011 types[i]=Type.getType(classes[i]); 1012 } 1013 return types; 1014 } 1015 1016 1017 public static String display(ExprString name) { 1018 if(name instanceof Literal) { 1019 if(name instanceof Identifier) 1020 return ((Identifier)name).getRaw(); 1021 return ((Literal)name).getString(); 1022 1023 } 1024 return name.toString(); 1025 } 1026 1027 1028 public static Literal cachedWithinValue(Expression val) throws EvaluatorException { 1029 if(val instanceof Literal) { 1030 Literal l=(Literal)val; 1031 1032 // double == days 1033 Double d = l.getDouble(null); 1034 if(d!=null) { 1035 return new LitLong(TimeSpanImpl.fromDays(d.doubleValue()).getMillis(), null, null); 1036 } 1037 1038 // request 1039 String str=l.getString(); 1040 if(str!=null && "request".equalsIgnoreCase(str.trim())) 1041 return new LitString("request",null,null); 1042 1043 throw cacheWithinException(); 1044 } 1045 // createTimespan 1046 else if(val instanceof Variable) { 1047 Variable var=(Variable)val; 1048 if(var.getMembers().size()==1) { 1049 Member first = var.getFirstMember(); 1050 if(first instanceof BIF) { 1051 BIF bif=(BIF) first; 1052 if("createTimeSpan".equalsIgnoreCase(bif.getFlf().getName())) { 1053 Argument[] args = bif.getArguments(); 1054 int len=ArrayUtil.size(args); 1055 if(len>=4 && len<=5) { 1056 double days=toDouble(args[0].getValue()); 1057 double hours=toDouble(args[1].getValue()); 1058 double minutes=toDouble(args[2].getValue()); 1059 double seconds=toDouble(args[3].getValue()); 1060 double millis=len==5?toDouble(args[4].getValue()):0; 1061 return new LitLong(new TimeSpanImpl((int)days,(int)hours,(int)minutes,(int)seconds,(int)millis).getMillis(),null,null); 1062 } 1063 } 1064 } 1065 } 1066 } 1067 throw cacheWithinException(); 1068 } 1069 1070 1071 1072 private static EvaluatorException cacheWithinException() { 1073 return new EvaluatorException("value of cachedWithin must be a literal timespan, like 0.1 or createTimespan(1,2,3,4) or the string \"request\" or the string \"smart\""); 1074 } 1075 1076 1077 private static double toDouble(Expression e) throws EvaluatorException { 1078 if(!(e instanceof Literal)) 1079 throw new EvaluatorException("Paremeters of the function createTimeSpan have to be literal numeric values in this context"); 1080 Double d = ((Literal)e).getDouble(null); 1081 if(d==null) 1082 throw new EvaluatorException("Paremeters of the function createTimeSpan have to be literal numeric values in this context"); 1083 1084 return d.doubleValue(); 1085 } 1086 1087 public static void visitLabel(GeneratorAdapter ga, Label label) { 1088 if(label!=null) ga.visitLabel(label); 1089 } 1090 1091 1092 1093 public static String getClassName(Resource res) throws IOException{ 1094 byte[] src=IOUtil.toBytes(res); 1095 ClassReader cr = new ClassReader(src); 1096 return cr.getClassName(); 1097 } 1098 1099 public static String getClassName(byte[] barr){ 1100 return new ClassReader(barr).getClassName(); 1101 } 1102 1103 1104 public static SourceInfo getSourceInfo(Config config,Class clazz, boolean onlyCFC) throws IOException { 1105 return SourceNameClassVisitor.getSourceInfo(config,clazz, onlyCFC); 1106 } 1107 1108 public static boolean hasOnlyDataMembers(Variable var) { 1109 Iterator<Member> it = var.getMembers().iterator(); 1110 Member m; 1111 while(it.hasNext()){ 1112 m = it.next(); 1113 if(!(m instanceof DataMember)) return false; 1114 } 1115 return true; 1116 } 1117 1118 1119 public static int count(List<Statement> statements, boolean recursive) { 1120 if(statements==null) return 0; 1121 int count=0; 1122 Iterator<Statement> it = statements.iterator(); 1123 while(it.hasNext()){ 1124 count+=count(it.next(),recursive); 1125 } 1126 return count; 1127 } 1128 1129 1130 public static int count(Statement s, boolean recursive) { 1131 int count=1; 1132 if(recursive && s instanceof HasBody) { 1133 Body b = ((HasBody) s).getBody(); 1134 if(b!=null) count+=count(b.getStatements(),recursive); 1135 } 1136 return count; 1137 } 1138 1139 public static void dump(Statement s, int level) { 1140 1141 for(int i=0;i<level;i++)System.err.print("-"); 1142 aprint.e(s.getClass().getName()); 1143 1144 if(s instanceof HasBody) { 1145 Body b = ((HasBody) s).getBody(); 1146 if(b!=null) { 1147 Iterator<Statement> it = b.getStatements().iterator(); 1148 while(it.hasNext()){ 1149 dump(it.next(),level+1); 1150 } 1151 } 1152 } 1153 } 1154 1155 1156 1157 public static void size(ClassWriter cw) { 1158 try { 1159 MethodVisitor mw=null; 1160 1161 Field[] fields = cw.getClass().getDeclaredFields(); 1162 Field f; 1163 for(int i=0;i<fields.length;i++){ 1164 f=fields[i]; 1165 if(f.getType().getName().equals("org.objectweb.asm.MethodWriter")) { 1166 f.setAccessible(true); 1167 mw = (MethodVisitor) f.get(cw); 1168 break; 1169 } 1170 } 1171 } 1172 catch (Throwable t) { 1173 ExceptionUtil.rethrowIfNecessary(t); 1174 // TODO Auto-generated catch block 1175 t.printStackTrace(); 1176 } 1177 } 1178 1179 1180 public static void createEmptyStruct(GeneratorAdapter adapter) { 1181 adapter.newInstance(Types.STRUCT_IMPL); 1182 adapter.dup(); 1183 adapter.invokeConstructor(Types.STRUCT_IMPL, Page.INIT_STRUCT_IMPL); 1184 } 1185 1186 public static void createEmptyArray(GeneratorAdapter adapter) { 1187 adapter.newInstance(Types.ARRAY_IMPL); 1188 adapter.dup(); 1189 adapter.invokeConstructor(Types.ARRAY_IMPL, Switch.INIT); 1190 } 1191}