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; 020 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026import java.util.Map.Entry; 027 028import lucee.commons.io.CharsetUtil; 029import lucee.commons.io.IOUtil; 030import lucee.commons.io.res.Resource; 031import lucee.commons.lang.StringUtil; 032import lucee.runtime.Mapping; 033import lucee.runtime.PageSource; 034import lucee.runtime.component.ImportDefintion; 035import lucee.runtime.component.ImportDefintionImpl; 036import lucee.runtime.config.Config; 037import lucee.runtime.engine.ThreadLocalPageContext; 038import lucee.runtime.exp.TemplateException; 039import lucee.runtime.type.KeyImpl; 040import lucee.runtime.type.UDF; 041import lucee.runtime.type.scope.Undefined; 042import lucee.runtime.type.util.KeyConstants; 043import lucee.transformer.bytecode.expression.Expression; 044import lucee.transformer.bytecode.literal.LitString; 045import lucee.transformer.bytecode.literal.LitString.Range; 046import lucee.transformer.bytecode.statement.Argument; 047import lucee.transformer.bytecode.statement.HasBodies; 048import lucee.transformer.bytecode.statement.HasBody; 049import lucee.transformer.bytecode.statement.IFunction; 050import lucee.transformer.bytecode.statement.NativeSwitch; 051import lucee.transformer.bytecode.statement.tag.Attribute; 052import lucee.transformer.bytecode.statement.tag.Tag; 053import lucee.transformer.bytecode.statement.tag.TagImport; 054import lucee.transformer.bytecode.statement.tag.TagThread; 055import lucee.transformer.bytecode.statement.udf.Function; 056import lucee.transformer.bytecode.statement.udf.FunctionImpl; 057import lucee.transformer.bytecode.util.ASMConstants; 058import lucee.transformer.bytecode.util.ASMUtil; 059import lucee.transformer.bytecode.util.ExpressionUtil; 060import lucee.transformer.bytecode.util.Types; 061import lucee.transformer.bytecode.visitor.ArrayVisitor; 062import lucee.transformer.bytecode.visitor.ConditionVisitor; 063import lucee.transformer.bytecode.visitor.DecisionIntVisitor; 064import lucee.transformer.bytecode.visitor.OnFinally; 065import lucee.transformer.bytecode.visitor.TryCatchFinallyVisitor; 066 067import org.objectweb.asm.ClassReader; 068import org.objectweb.asm.ClassVisitor; 069import org.objectweb.asm.ClassWriter; 070import org.objectweb.asm.FieldVisitor; 071import org.objectweb.asm.Label; 072import org.objectweb.asm.MethodVisitor; 073import org.objectweb.asm.Opcodes; 074import org.objectweb.asm.Type; 075import org.objectweb.asm.commons.GeneratorAdapter; 076import org.objectweb.asm.commons.Method; 077 078/** 079 * represent a single Page like "index.cfm" 080 */ 081public final class Page extends BodyBase { 082 083 084 public void doFinalize(BytecodeContext bc) { 085 ExpressionUtil.visitLine(bc, getEnd()); 086 } 087 088 public static final Type NULL = Type.getType(lucee.runtime.type.Null.class); 089 public static final Type KEY_IMPL = Type.getType(KeyImpl.class); 090 public static final Type KEY_CONSTANTS = Type.getType(KeyConstants.class); 091 public static final Method KEY_INIT = new Method( 092 "init", 093 Types.COLLECTION_KEY, 094 new Type[]{Types.STRING} 095 ); 096 public static final Method KEY_INTERN = new Method( 097 "intern", 098 Types.COLLECTION_KEY, 099 new Type[]{Types.STRING} 100 ); 101 102 // public static ImportDefintion getInstance(String fullname,ImportDefintion defaultValue) 103 private static final Method ID_GET_INSTANCE = new Method( 104 "getInstance", 105 Types.IMPORT_DEFINITIONS, 106 new Type[]{Types.STRING,Types.IMPORT_DEFINITIONS} 107 ); 108 109 public final static Method STATIC_CONSTRUCTOR = Method.getMethod("void <clinit> ()V"); 110 //public final static Method CONSTRUCTOR = Method.getMethod("void <init> ()V"); 111 112 private static final Method CONSTRUCTOR = new Method( 113 "<init>", 114 Types.VOID, 115 new Type[]{}// 116 ); 117 private static final Method CONSTRUCTOR_PS = new Method( 118 "<init>", 119 Types.VOID, 120 new Type[]{Types.PAGE_SOURCE}// 121 ); 122 123 public static final Method INIT_STRUCT_IMPL = new Method( 124 "<init>", 125 Types.VOID, 126 new Type[]{} 127 ); 128 129 130 // void call (lucee.runtime.PageContext) 131 private final static Method CALL = new Method( 132 "call", 133 Types.VOID, 134 new Type[]{Types.PAGE_CONTEXT} 135 ); 136 137 /*/ void _try () 138 private final static Method TRY = new Method( 139 "_try", 140 Types.VOID, 141 new Type[]{} 142 );*/ 143 144 // int getVersion() 145 private final static Method VERSION = new Method( 146 "getVersion", 147 Types.INT_VALUE, 148 new Type[]{} 149 ); 150 // void _init() 151 private final static Method _INIT = new Method( 152 "initKeys", 153 Types.VOID, 154 new Type[]{} 155 ); 156 157 private final static Method SET_PAGE_SOURCE = new Method( 158 "setPageSource", 159 Types.VOID, 160 new Type[]{Types.PAGE_SOURCE} 161 ); 162 163 // public ImportDefintion[] getImportDefintions() 164 private final static Method GET_IMPORT_DEFINITIONS = new Method( 165 "getImportDefintions", 166 Types.IMPORT_DEFINITIONS_ARRAY, 167 new Type[]{} 168 ); 169 170 // long getSourceLastModified() 171 private final static Method LAST_MOD = new Method( 172 "getSourceLastModified", 173 Types.LONG_VALUE, 174 new Type[]{} 175 ); 176 177 private final static Method COMPILE_TIME = new Method( 178 "getCompileTime", 179 Types.LONG_VALUE, 180 new Type[]{} 181 ); 182 183 private static final Type USER_DEFINED_FUNCTION = Type.getType(UDF.class); 184 private static final Method UDF_CALL = new Method( 185 "udfCall", 186 Types.OBJECT, 187 new Type[]{Types.PAGE_CONTEXT, USER_DEFINED_FUNCTION, Types.INT_VALUE} 188 ); 189 190 191 private static final Method THREAD_CALL = new Method( 192 "threadCall", 193 Types.VOID, 194 new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE} 195 ); 196 197 /*private static final Method UDF_DEFAULT_VALUE = new Method( 198 "udfDefaultValue", 199 Types.OBJECT, 200 new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE} 201 );*/ 202 203 private static final Method UDF_DEFAULT_VALUE = new Method( 204 "udfDefaultValue", 205 Types.OBJECT, 206 new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE,Types.OBJECT} 207 ); 208 209 private static final Method NEW_COMPONENT_IMPL_INSTANCE = new Method( 210 "newInstance", 211 Types.COMPONENT_IMPL, 212 new Type[]{Types.PAGE_CONTEXT,Types.STRING,Types.BOOLEAN_VALUE} 213 ); 214 215 private static final Method NEW_INTERFACE_IMPL_INSTANCE = new Method( 216 "newInstance", 217 Types.INTERFACE_IMPL, 218 new Type[]{Types.STRING,Types.BOOLEAN_VALUE,Types.MAP} 219 ); 220 221 222 223 224 225 // void init(PageContext pc,Component Impl c) throws PageException 226 private static final Method INIT_COMPONENT = new Method( 227 "initComponent", 228 Types.VOID, 229 new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_IMPL} 230 ); 231 private static final Method INIT_INTERFACE = new Method( 232 "initInterface", 233 Types.VOID, 234 new Type[]{Types.INTERFACE_IMPL} 235 ); 236 237 238 // public boolean setMode(int mode) { 239 private static final Method SET_MODE = new Method( 240 "setMode", 241 Types.INT_VALUE, 242 new Type[]{Types.INT_VALUE} 243 ); 244 245 246 247 248 249 250 251 252 private static final Method CONSTR_INTERFACE_IMPL = new Method( 253 "<init>", 254 Types.VOID, 255 new Type[]{ 256 Types.INTERFACE_PAGE, 257 Types.STRING, // extends 258 Types.STRING, // hind 259 Types.STRING, // display 260 Types.STRING, // callpath 261 Types.BOOLEAN_VALUE, // relpath 262 Types.MAP, //interfaceudfs 263 Types.MAP // meta 264 } 265 ); 266 267 268 //void init(PageContext pageContext,ComponentPage componentPage) 269 private static final Method INIT = new Method( 270 "init", 271 Types.VOID, 272 new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_PAGE} 273 ); 274 275 private static final Method CHECK_INTERFACE = new Method( 276 "checkInterface", 277 Types.VOID, 278 new Type[]{Types.PAGE_CONTEXT,Types.COMPONENT_PAGE} 279 ); 280 281 282 283 // boolean getOutput() 284 private static final Method GET_OUTPUT = new Method( 285 "getOutput", 286 Types.BOOLEAN_VALUE, 287 new Type[]{} 288 ); 289 290 291 private static final Method PUSH_BODY = new Method( 292 "pushBody", 293 Types.BODY_CONTENT, 294 new Type[]{} 295 ); 296 297 /*/ boolean setSilent() 298 private static final Method SET_SILENT = new Method( 299 "setSilent", 300 Types.BOOLEAN_VALUE, 301 new Type[]{} 302 ); 303*/ 304 // Scope beforeCall(PageContext pc) 305 private static final Method BEFORE_CALL = new Method( 306 "beforeCall", 307 Types.VARIABLES, 308 new Type[]{Types.PAGE_CONTEXT} 309 ); 310 311 private static final Method TO_PAGE_EXCEPTION = new Method( 312 "toPageException", 313 Types.PAGE_EXCEPTION, 314 new Type[]{Types.THROWABLE}); 315 316 317 // boolean unsetSilent() 318 /*private static final Method UNSET_SILENT = new Method( 319 "unsetSilent", 320 Types.BOOLEAN_VALUE, 321 new Type[]{} 322 );*/ 323 324 // void afterCall(PageContext pc, Scope parent) 325 private static final Method AFTER_CALL = new Method( 326 "afterConstructor", 327 Types.VOID, 328 new Type[]{Types.PAGE_CONTEXT,Types.VARIABLES} 329 ); 330 331 // ComponentImpl(ComponentPage,boolean, String, String, String) NS==No Style 332 333 334 // Component Impl(ComponentPage,boolean, String, String, String, String) WS==With Style 335 private static final Method CONSTR_COMPONENT_IMPL = new Method( 336 "<init>", 337 Types.VOID, 338 new Type[]{ 339 Types.COMPONENT_PAGE, 340 Types.BOOLEAN, 341 Types.BOOLEAN_VALUE, 342 Types.STRING, 343 Types.STRING, 344 Types.STRING, 345 Types.STRING, 346 Types.STRING, 347 Types.BOOLEAN_VALUE, 348 Types.STRING, 349 Types.BOOLEAN_VALUE, 350 Types.BOOLEAN_VALUE, 351 Types.STRUCT_IMPL 352 } 353 ); 354 private static final Method SET_EL = new Method( 355 "setEL", 356 Types.OBJECT, 357 new Type[]{Types.STRING,Types.OBJECT} 358 ); 359 private static final Method UNDEFINED_SCOPE = new Method( 360 "us", 361 Types.UNDEFINED, 362 new Type[]{} 363 ); 364 private static final Method FLUSH_AND_POP = new Method( 365 "flushAndPop", 366 Types.VOID, 367 new Type[]{Types.PAGE_CONTEXT,Types.BODY_CONTENT} 368 ); 369 private static final Method CLEAR_AND_POP = new Method( 370 "clearAndPop", 371 Types.VOID, 372 new Type[]{Types.PAGE_CONTEXT,Types.BODY_CONTENT} 373 ); 374 public static final byte CF = (byte)207; 375 public static final byte _33 = (byte)51; 376 //private static final boolean ADD_C33 = false; 377 //private static final String SUB_CALL_UDF = "udfCall"; 378 private static final String SUB_CALL_UDF = "_"; 379 private static final int DEFAULT_VALUE = 3; 380 381 private final int version; 382 private final long lastModifed; 383 private final boolean _writeLog; 384 private final String name; 385 private final boolean suppressWSbeforeArg; 386 private final boolean output; 387 private final PageSource pageSource; 388 389 private boolean isComponent; 390 private boolean isInterface; 391 392 private ArrayList<IFunction> functions=new ArrayList<IFunction>(); 393 private ArrayList<TagThread> threads=new ArrayList<TagThread>(); 394 private Resource staticTextLocation; 395 private int off; 396 private int methodCount=0; 397 //private final Config config; 398 private boolean splitIfNecessary; 399 400 401 402 public Page(PageSource pageSource,Resource source,String name,int version, long lastModifed, boolean writeLog, boolean suppressWSbeforeArg, boolean output) { 403 name=name.replace('.', '/'); 404 this.name=name; 405 this.version=version; 406 this.lastModifed=lastModifed; 407 408 this._writeLog=writeLog; 409 this.suppressWSbeforeArg=suppressWSbeforeArg; 410 this.output=output; 411 this.pageSource=pageSource; 412 } 413 414 /** 415 * result byte code as binary array 416 * @param classFile 417 * @return byte code 418 * @throws IOException 419 * @throws TemplateException 420 */ 421 public byte[] execute(PageSource source,Resource classFile) throws BytecodeException { 422 /* 423 // this is done that the Page can be executed more than once 424 if(initFunctions==null) 425 initFunctions=(ArrayList<IFunction>) functions.clone(); 426 else 427 functions=initFunctions; 428 if(initThreads==null) 429 initThreads=(ArrayList<TagThread>) threads.clone(); 430 else 431 threads=initThreads; 432 methodCount=0; 433 off=0; 434 staticTextLocation=null; 435 436 437 print.e(this.functions); 438 print.e(this.threads);*/ 439 440 441 Resource p = classFile.getParentResource().getRealResource(classFile.getName()+".txt"); 442 443 List<LitString> keys=new ArrayList<LitString>(); 444 ClassWriter cw = ASMUtil.getClassWriter(); 445 446 ArrayList<String> imports = new ArrayList<String>(); 447 getImports(imports, this); 448 449 // parent 450 String parent="lucee/runtime/PagePlus"; 451 if(isComponent()) parent="lucee/runtime/ComponentPage"; 452 else if(isInterface()) parent="lucee/runtime/InterfacePage"; 453 454 cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL, name, null, parent, null); 455 Mapping m = source!=null?source.getMapping():null; 456 Config config = m!=null?m.getConfig():null; 457 if(config==null) config=ThreadLocalPageContext.getConfig(); 458 String path=config.allowRequestTimeout()? 459 pageSource.getFullRealpath():pageSource.getPhyscalFile().getAbsolutePath(); 460 461 cw.visitSource(path,null); // when adding more use ; as delimiter 462 463 // static constructor 464 //GeneratorAdapter statConstrAdapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,STATIC_CONSTRUCTOR,null,null,cw); 465 BytecodeContext statConstr = null;//new BytecodeContext(null,null,this,externalizer,keys,cw,name,statConstrAdapter,STATIC_CONSTRUCTOR,writeLog(),suppressWSbeforeArg); 466 467 // constructor 468 GeneratorAdapter constrAdapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR_PS,null,null,cw); 469 BytecodeContext constr = new BytecodeContext(source,null,null,this,keys,cw,name,constrAdapter,CONSTRUCTOR_PS,writeLog(),suppressWSbeforeArg,output); 470 constrAdapter.loadThis(); 471 Type t=Types.PAGE_PLUS; 472 if(isComponent())t=Types.COMPONENT_PAGE; 473 else if(isInterface())t=Types.INTERFACE_PAGE; 474 475 constrAdapter.invokeConstructor(t, CONSTRUCTOR); 476 477 // call _init() 478 constrAdapter.visitVarInsn(Opcodes.ALOAD, 0); 479 constrAdapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, constr.getClassName(), "initKeys", "()V"); 480 481 // private static ImportDefintion[] test=new ImportDefintion[]{...}; 482 { 483 FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, 484 "imports", "[Llucee/runtime/component/ImportDefintion;", null, null); 485 fv.visitEnd(); 486 487 constrAdapter.visitVarInsn(Opcodes.ALOAD, 0); 488 ArrayVisitor av=new ArrayVisitor(); 489 av.visitBegin(constrAdapter,Types.IMPORT_DEFINITIONS,imports.size()); 490 int index=0; 491 Iterator<String> it = imports.iterator(); 492 while(it.hasNext()){ 493 av.visitBeginItem(constrAdapter,index++); 494 constrAdapter.push(it.next()); 495 ASMConstants.NULL(constrAdapter); 496 constrAdapter.invokeStatic(Types.IMPORT_DEFINITIONS_IMPL, ID_GET_INSTANCE); 497 av.visitEndItem(constrAdapter); 498 } 499 av.visitEnd(); 500 constrAdapter.visitFieldInsn(Opcodes.PUTFIELD, name, "imports", "[Llucee/runtime/component/ImportDefintion;"); 501 502 } 503 504 505 506 507 // getVersion 508 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , VERSION, null, null, cw); 509 adapter.push(version); 510 adapter.returnValue(); 511 adapter.endMethod(); 512 513 514 // public ImportDefintion[] getImportDefintions() 515 if(imports.size()>0){ 516 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , GET_IMPORT_DEFINITIONS, null, null, cw); 517 adapter.visitVarInsn(Opcodes.ALOAD, 0); 518 adapter.visitFieldInsn(Opcodes.GETFIELD, name, "imports", "[Llucee/runtime/component/ImportDefintion;"); 519 adapter.returnValue(); 520 adapter.endMethod(); 521 } 522 else { 523 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , GET_IMPORT_DEFINITIONS, null, null, cw); 524 adapter.visitInsn(Opcodes.ICONST_0); 525 adapter.visitTypeInsn(Opcodes.ANEWARRAY, "lucee/runtime/component/ImportDefintion"); 526 adapter.returnValue(); 527 adapter.endMethod(); 528 } 529 530 531 // getSourceLastModified 532 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , LAST_MOD, null, null, cw); 533 adapter.push(lastModifed); 534 adapter.returnValue(); 535 adapter.endMethod(); 536 537 // getCompileTime 538 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , COMPILE_TIME, null, null, cw); 539 adapter.push(System.currentTimeMillis()); 540 adapter.returnValue(); 541 adapter.endMethod(); 542 543 // newInstance/initComponent/call 544 if(isComponent()) { 545 Tag component=getComponent(); 546 writeOutNewComponent(statConstr,constr,keys,cw,component); 547 writeOutInitComponent(statConstr,constr,keys,cw,component); 548 } 549 else if(isInterface()) { 550 Tag interf=getInterface(); 551 writeOutNewInterface(statConstr,constr,keys,cw,interf); 552 writeOutInitInterface(statConstr,constr,keys,cw,interf); 553 } 554 else { 555 writeOutCall(statConstr,constr,keys,cw); 556 } 557 558// udfCall 559 Function[] functions=getFunctions(); 560 ConditionVisitor cv; 561 DecisionIntVisitor div; 562 // less/equal than 10 functions 563 if(isInterface()){} 564 else if(functions.length<=10) { 565 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_CALL, null, new Type[]{Types.THROWABLE}, cw); 566 BytecodeContext bc = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_CALL,writeLog(),suppressWSbeforeArg,output); 567 if(functions.length==0){} 568 else if(functions.length==1){ 569 ExpressionUtil.visitLine(bc,functions[0].getStart()); 570 functions[0].getBody().writeOut(bc); 571 ExpressionUtil.visitLine(bc,functions[0].getEnd()); 572 } 573 else writeOutUdfCallInner(bc,functions,0,functions.length); 574 adapter.visitInsn(Opcodes.ACONST_NULL); 575 adapter.returnValue(); 576 adapter.endMethod(); 577 } 578 // more than 10 functions 579 else { 580 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_CALL, null, new Type[]{Types.THROWABLE}, cw); 581 BytecodeContext bc = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_CALL,writeLog(),suppressWSbeforeArg,output); 582 cv = new ConditionVisitor(); 583 cv.visitBefore(); 584 int count=0; 585 for(int i=0;i<functions.length;i+=10) { 586 cv.visitWhenBeforeExpr(); 587 div=new DecisionIntVisitor(); 588 div.visitBegin(); 589 adapter.loadArg(2); 590 div.visitLT(); 591 adapter.push(i+10); 592 div.visitEnd(bc); 593 cv.visitWhenAfterExprBeforeBody(bc); 594 595 adapter.visitVarInsn(Opcodes.ALOAD, 0); 596 adapter.visitVarInsn(Opcodes.ALOAD, 1); 597 adapter.visitVarInsn(Opcodes.ALOAD, 2); 598 adapter.visitVarInsn(Opcodes.ILOAD, 3); 599 adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, name, createFunctionName(++count), "(Llucee/runtime/PageContext;Llucee/runtime/type/UDF;I)Ljava/lang/Object;"); 600 adapter.visitInsn(Opcodes.ARETURN);//adapter.returnValue(); 601 cv.visitWhenAfterBody(bc); 602 } 603 cv.visitAfter(bc); 604 605 adapter.visitInsn(Opcodes.ACONST_NULL); 606 adapter.returnValue(); 607 adapter.endMethod(); 608 609 count=0; 610 Method innerCall; 611 for(int i=0;i<functions.length;i+=10) { 612 innerCall = new Method(createFunctionName(++count),Types.OBJECT,new Type[]{Types.PAGE_CONTEXT, USER_DEFINED_FUNCTION, Types.INT_VALUE}); 613 614 adapter = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , innerCall, null, new Type[]{Types.THROWABLE}, cw); 615 writeOutUdfCallInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,innerCall,writeLog(),suppressWSbeforeArg,output), functions, i, i+10>functions.length?functions.length:i+10); 616 617 adapter.visitInsn(Opcodes.ACONST_NULL); 618 adapter.returnValue(); 619 adapter.endMethod(); 620 } 621 } 622 623 624 // threadCall 625 TagThread[] threads=getThreads(); 626 if(true) { 627 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , THREAD_CALL, null, new Type[]{Types.THROWABLE}, cw); 628 if(threads.length>0) writeOutThreadCallInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,THREAD_CALL,writeLog(),suppressWSbeforeArg,output),threads,0,threads.length); 629 //adapter.visitInsn(Opcodes.ACONST_NULL); 630 adapter.returnValue(); 631 adapter.endMethod(); 632 } 633 634 635 636 637// udfDefaultValue 638 // less/equal than 10 functions 639 if(isInterface()) {} 640 else if(functions.length<=10) { 641 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_DEFAULT_VALUE, null, new Type[]{Types.PAGE_EXCEPTION}, cw); 642 if(functions.length>0) 643 writeUdfDefaultValueInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_DEFAULT_VALUE,writeLog(),suppressWSbeforeArg,output),functions,0,functions.length); 644 645 adapter.loadArg(DEFAULT_VALUE); 646 adapter.returnValue(); 647 adapter.endMethod(); 648 } 649 else { 650 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , UDF_DEFAULT_VALUE, null, new Type[]{Types.PAGE_EXCEPTION}, cw); 651 BytecodeContext bc = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,UDF_DEFAULT_VALUE,writeLog(),suppressWSbeforeArg,output); 652 cv = new ConditionVisitor(); 653 cv.visitBefore(); 654 int count=0; 655 for(int i=0;i<functions.length;i+=10) { 656 cv.visitWhenBeforeExpr(); 657 div=new DecisionIntVisitor(); 658 div.visitBegin(); 659 adapter.loadArg(1); 660 div.visitLT(); 661 adapter.push(i+10); 662 div.visitEnd(bc); 663 cv.visitWhenAfterExprBeforeBody(bc); 664 665 adapter.visitVarInsn(Opcodes.ALOAD, 0); 666 adapter.visitVarInsn(Opcodes.ALOAD, 1); 667 adapter.visitVarInsn(Opcodes.ILOAD, 2); 668 adapter.visitVarInsn(Opcodes.ILOAD, 3); 669 adapter.visitVarInsn(Opcodes.ALOAD, 4); 670 671 adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, name, "udfDefaultValue"+(++count), "(Llucee/runtime/PageContext;IILjava/lang/Object;)Ljava/lang/Object;"); 672 adapter.visitInsn(Opcodes.ARETURN);//adapter.returnValue(); 673 674 cv.visitWhenAfterBody(bc); 675 } 676 cv.visitAfter(bc); 677 678 adapter.visitInsn(Opcodes.ACONST_NULL); 679 adapter.returnValue(); 680 adapter.endMethod(); 681 682 count=0; 683 Method innerDefaultValue; 684 for(int i=0;i<functions.length;i+=10) { 685 innerDefaultValue = new Method("udfDefaultValue"+(++count),Types.OBJECT,new Type[]{Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE,Types.OBJECT}); 686 adapter = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , innerDefaultValue, null, new Type[]{Types.PAGE_EXCEPTION}, cw); 687 writeUdfDefaultValueInner(new BytecodeContext(source,statConstr,constr,this,keys,cw,name,adapter,innerDefaultValue,writeLog(),suppressWSbeforeArg,output), functions, i, i+10>functions.length?functions.length:i+10); 688 689 adapter.loadArg(DEFAULT_VALUE); 690 //adapter.visitInsn(Opcodes.ACONST_NULL); 691 adapter.returnValue(); 692 adapter.endMethod(); 693 } 694 695 } 696 697 698 // register fields 699 { 700 GeneratorAdapter aInit = new GeneratorAdapter(Opcodes.ACC_PRIVATE+Opcodes.ACC_FINAL , _INIT, null, null, cw); 701 BytecodeContext bcInit = new BytecodeContext(source,statConstr,constr,this,keys,cw,name,aInit,_INIT,writeLog(),suppressWSbeforeArg,output); 702 registerFields(bcInit,keys); 703 aInit.returnValue(); 704 aInit.endMethod(); 705 } 706 707 //setPageSource(pageSource); 708 constrAdapter.visitVarInsn(Opcodes.ALOAD, 0); 709 constrAdapter.visitVarInsn(Opcodes.ALOAD, 1); 710 constrAdapter.invokeVirtual(t, SET_PAGE_SOURCE); 711 712 713 constrAdapter.returnValue(); 714 constrAdapter.endMethod(); 715 716 return cw.toByteArray(); 717 718 } 719 720 721 722 723 private String createFunctionName(int i) { 724 return "udfCall"+Integer.toString(i, Character.MAX_RADIX); 725 } 726 727 private boolean writeLog() { 728 return _writeLog && !isInterface(); 729 } 730 731 public static void registerFields(BytecodeContext bc, List<LitString> keys) throws BytecodeException { 732 //if(keys.size()==0) return; 733 GeneratorAdapter ga = bc.getAdapter(); 734 735 FieldVisitor fv = bc.getClassWriter().visitField(Opcodes.ACC_PRIVATE , 736 "keys", Types.COLLECTION_KEY_ARRAY.toString(), null, null); 737 fv.visitEnd(); 738 739 int index=0; 740 LitString value; 741 Iterator<LitString> it = keys.iterator(); 742 ga.visitVarInsn(Opcodes.ALOAD, 0); 743 ga.push(keys.size()); 744 ga.newArray(Types.COLLECTION_KEY); 745 while(it.hasNext()) { 746 value=it.next(); 747 ga.dup(); 748 ga.push(index++); 749 //value.setExternalize(false); 750 ExpressionUtil.writeOutSilent(value,bc, Expression.MODE_REF); 751 ga.invokeStatic(KEY_IMPL, KEY_INTERN); 752 ga.visitInsn(Opcodes.AASTORE); 753 } 754 ga.visitFieldInsn(Opcodes.PUTFIELD, bc.getClassName(), "keys", Types.COLLECTION_KEY_ARRAY.toString()); 755 } 756 757 private void writeUdfDefaultValueInner(BytecodeContext bc, Function[] functions, int offset, int length) throws BytecodeException { 758 GeneratorAdapter adapter = bc.getAdapter(); 759 ConditionVisitor cv = new ConditionVisitor(); 760 DecisionIntVisitor div; 761 cv.visitBefore(); 762 for(int i=offset;i<length;i++) { 763 cv.visitWhenBeforeExpr(); 764 div = new DecisionIntVisitor(); 765 div.visitBegin(); 766 adapter.loadArg(1); 767 div.visitEQ(); 768 adapter.push(i); 769 div.visitEnd(bc); 770 cv.visitWhenAfterExprBeforeBody(bc); 771 writeOutFunctionDefaultValueInnerInner(bc, functions[i]); 772 cv.visitWhenAfterBody(bc); 773 } 774 cv.visitAfter(bc); 775 } 776 777 778 private void writeOutUdfCallInnerIf(BytecodeContext bc,Function[] functions, int offset, int length) throws BytecodeException { 779 GeneratorAdapter adapter = bc.getAdapter(); 780 ConditionVisitor cv=new ConditionVisitor(); 781 DecisionIntVisitor div; 782 cv.visitBefore(); 783 for(int i=offset;i<length;i++) { 784 cv.visitWhenBeforeExpr(); 785 div=new DecisionIntVisitor(); 786 div.visitBegin(); 787 adapter.loadArg(2); 788 div.visitEQ(); 789 adapter.push(i); 790 div.visitEnd(bc); 791 cv.visitWhenAfterExprBeforeBody(bc); 792 ExpressionUtil.visitLine(bc, functions[i].getStart()); 793 functions[i].getBody().writeOut(bc); 794 ExpressionUtil.visitLine(bc, functions[i].getEnd()); 795 cv.visitWhenAfterBody(bc); 796 } 797 cv.visitAfter(bc); 798 } 799 800 private void writeOutUdfCallInner(BytecodeContext bc,Function[] functions, int offset, int length) throws BytecodeException { 801 NativeSwitch ns=new NativeSwitch(2,NativeSwitch.ARG_REF,null,null); 802 803 for(int i=offset;i<length;i++) { 804 ns.addCase(i, functions[i].getBody(),functions[i].getStart(),functions[i].getEnd(),true); 805 } 806 ns._writeOut(bc); 807 } 808 809 810 811 private void writeOutThreadCallInner(BytecodeContext bc,TagThread[] threads, int offset, int length) throws BytecodeException { 812 GeneratorAdapter adapter = bc.getAdapter(); 813 ConditionVisitor cv=new ConditionVisitor(); 814 DecisionIntVisitor div; 815 cv.visitBefore(); 816 //print.ln("functions:"+functions.length); 817 for(int i=offset;i<length;i++) { 818 cv.visitWhenBeforeExpr(); 819 div=new DecisionIntVisitor(); 820 div.visitBegin(); 821 adapter.loadArg(1); 822 div.visitEQ(); 823 adapter.push(i); 824 div.visitEnd(bc); 825 cv.visitWhenAfterExprBeforeBody(bc); 826 Body body = threads[i].getRealBody(); 827 if(body!=null)body.writeOut(bc); 828 cv.visitWhenAfterBody(bc); 829 } 830 cv.visitAfter(bc); 831 } 832 833 private void writeOutInitComponent(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys, ClassWriter cw, Tag component) throws BytecodeException { 834 final GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , INIT_COMPONENT, null, new Type[]{Types.PAGE_EXCEPTION}, cw); 835 BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,INIT_COMPONENT,writeLog(),suppressWSbeforeArg,output); 836 Label methodBegin=new Label(); 837 Label methodEnd=new Label(); 838 839 adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0); 840 adapter.visitLabel(methodBegin); 841 842 // Scope oldData=null; 843 final int oldData=adapter.newLocal(Types.VARIABLES); 844 ASMConstants.NULL(adapter); 845 adapter.storeLocal(oldData); 846 847 int localBC=adapter.newLocal(Types.BODY_CONTENT); 848 ConditionVisitor cv=new ConditionVisitor(); 849 cv.visitBefore(); 850 cv.visitWhenBeforeExpr(); 851 adapter.loadArg(1); 852 adapter.invokeVirtual(Types.COMPONENT_IMPL, GET_OUTPUT); 853 cv.visitWhenAfterExprBeforeBody(bc); 854 ASMConstants.NULL(adapter); 855 cv.visitWhenAfterBody(bc); 856 857 cv.visitOtherviseBeforeBody(); 858 adapter.loadArg(0); 859 adapter.invokeVirtual(Types.PAGE_CONTEXT, PUSH_BODY); 860 cv.visitOtherviseAfterBody(); 861 cv.visitAfter(bc); 862 adapter.storeLocal(localBC); 863 864 // c.init(pc,this); 865 adapter.loadArg(1); 866 adapter.loadArg(0); 867 adapter.visitVarInsn(Opcodes.ALOAD, 0); 868 adapter.invokeVirtual(Types.COMPONENT_IMPL, INIT); 869 870 871 //int oldCheckArgs= pc.undefinedScope().setMode(Undefined.MODE_NO_LOCAL_AND_ARGUMENTS); 872 final int oldCheckArgs = adapter.newLocal(Types.INT_VALUE); 873 adapter.loadArg(0); 874 adapter.invokeVirtual(Types.PAGE_CONTEXT, UNDEFINED_SCOPE); 875 adapter.push(Undefined.MODE_NO_LOCAL_AND_ARGUMENTS); 876 adapter.invokeInterface(Types.UNDEFINED, SET_MODE); 877 adapter.storeLocal(oldCheckArgs); 878 879 880 TryCatchFinallyVisitor tcf=new TryCatchFinallyVisitor(new OnFinally() { 881 882 public void _writeOut(BytecodeContext bc) { 883 884 // undefined.setMode(oldMode); 885 adapter.loadArg(0); 886 adapter.invokeVirtual(Types.PAGE_CONTEXT, UNDEFINED_SCOPE); 887 adapter.loadLocal(oldCheckArgs,Types.INT_VALUE); 888 adapter.invokeInterface(Types.UNDEFINED, SET_MODE); 889 adapter.pop(); 890 891 // c.afterCall(pc,_oldData); 892 adapter.loadArg(1); 893 adapter.loadArg(0); 894 adapter.loadLocal(oldData); 895 adapter.invokeVirtual(Types.COMPONENT_IMPL, AFTER_CALL); 896 897 898 } 899 },null); 900 tcf.visitTryBegin(bc); 901 // oldData=c.beforeCall(pc); 902 adapter.loadArg(1); 903 adapter.loadArg(0); 904 adapter.invokeVirtual(Types.COMPONENT_IMPL, BEFORE_CALL); 905 adapter.storeLocal(oldData); 906 ExpressionUtil.visitLine(bc, component.getStart()); 907 writeOutCallBody(bc,component.getBody(),IFunction.PAGE_TYPE_COMPONENT); 908 ExpressionUtil.visitLine(bc, component.getEnd()); 909 int t = tcf.visitTryEndCatchBeging(bc); 910 // BodyContentUtil.flushAndPop(pc,bc); 911 adapter.loadArg(0); 912 adapter.loadLocal(localBC); 913 adapter.invokeStatic(Types.BODY_CONTENT_UTIL, FLUSH_AND_POP); 914 915 // throw Caster.toPageException(t); 916 adapter.loadLocal(t); 917 adapter.invokeStatic(Types.CASTER, TO_PAGE_EXCEPTION); 918 adapter.throwException(); 919 tcf.visitCatchEnd(bc); 920 921 adapter.loadArg(0); 922 adapter.loadLocal(localBC); 923 adapter.invokeStatic(Types.BODY_CONTENT_UTIL, CLEAR_AND_POP); 924 925 adapter.returnValue(); 926 adapter.visitLabel(methodEnd); 927 928 adapter.endMethod(); 929 930 } 931 932 private void writeOutInitInterface(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys, ClassWriter cw, Tag interf) throws BytecodeException { 933 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , INIT_INTERFACE, null, new Type[]{Types.PAGE_EXCEPTION}, cw); 934 BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,INIT_INTERFACE,writeLog(),suppressWSbeforeArg,output); 935 Label methodBegin=new Label(); 936 Label methodEnd=new Label(); 937 938 adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0); 939 adapter.visitLabel(methodBegin); 940 941 ExpressionUtil.visitLine(bc, interf.getStart()); 942 writeOutCallBody(bc,interf.getBody(),IFunction.PAGE_TYPE_INTERFACE); 943 ExpressionUtil.visitLine(bc, interf.getEnd()); 944 945 adapter.returnValue(); 946 adapter.visitLabel(methodEnd); 947 948 adapter.endMethod(); 949 950 } 951 952 private Tag getComponent() throws BytecodeException { 953 Iterator it = getStatements().iterator(); 954 Statement s; 955 Tag t; 956 while(it.hasNext()) { 957 s=(Statement)it.next(); 958 if(s instanceof Tag) { 959 t=(Tag)s; 960 if(t.getTagLibTag().getTagClassName().equals("lucee.runtime.tag.Component"))return t; 961 } 962 } 963 throw new BytecodeException("missing component",getStart()); 964 } 965 private Tag getInterface() throws BytecodeException { 966 Iterator it = getStatements().iterator(); 967 Statement s; 968 Tag t; 969 while(it.hasNext()) { 970 s=(Statement)it.next(); 971 if(s instanceof Tag) { 972 t=(Tag)s; 973 if(t.getTagLibTag().getTagClassName().equals("lucee.runtime.tag.Interface"))return t; 974 } 975 } 976 throw new BytecodeException("missing interface",getStart()); 977 } 978 979 private void writeOutFunctionDefaultValueInnerInner(BytecodeContext bc, Function function) throws BytecodeException { 980 GeneratorAdapter adapter = bc.getAdapter(); 981 982 List<Argument> args = function.getArguments(); 983 984 if(args.size()==0) { 985 adapter.loadArg(DEFAULT_VALUE); 986 adapter.returnValue(); 987 return; 988 } 989 990 Iterator<Argument> it = args.iterator(); 991 Argument arg; 992 ConditionVisitor cv=new ConditionVisitor(); 993 DecisionIntVisitor div; 994 cv.visitBefore(); 995 int count=0; 996 while(it.hasNext()) { 997 arg=it.next(); 998 cv.visitWhenBeforeExpr(); 999 div=new DecisionIntVisitor(); 1000 div.visitBegin(); 1001 adapter.loadArg(2); 1002 div.visitEQ(); 1003 adapter.push(count++); 1004 div.visitEnd(bc); 1005 cv.visitWhenAfterExprBeforeBody(bc); 1006 Expression defaultValue = arg.getDefaultValue(); 1007 if(defaultValue!=null) { 1008 /*if(defaultValue instanceof Null) { 1009 adapter.invokeStatic(NULL, GET_INSTANCE); 1010 } 1011 else*/ 1012 defaultValue.writeOut(bc, Expression.MODE_REF); 1013 } 1014 else 1015 adapter.loadArg(DEFAULT_VALUE); 1016 //adapter.visitInsn(Opcodes.ACONST_NULL); 1017 adapter.returnValue(); 1018 cv.visitWhenAfterBody(bc); 1019 } 1020 cv.visitOtherviseBeforeBody(); 1021 //adapter.visitInsn(ACONST_NULL); 1022 //adapter.returnValue(); 1023 cv.visitOtherviseAfterBody(); 1024 cv.visitAfter(bc); 1025 } 1026 1027 private Function[] getFunctions() { 1028 Function[] funcs=new Function[functions.size()]; 1029 Iterator it = functions.iterator(); 1030 int count=0; 1031 while(it.hasNext()) { 1032 funcs[count++]=(Function) it.next(); 1033 } 1034 return funcs; 1035 } 1036 1037 private TagThread[] getThreads() { 1038 TagThread[] threads=new TagThread[this.threads.size()]; 1039 Iterator it = this.threads.iterator(); 1040 int count=0; 1041 while(it.hasNext()) { 1042 threads[count++]=(TagThread) it.next(); 1043 } 1044 return threads; 1045 } 1046 1047 1048 public void _writeOut(BytecodeContext bc) throws BytecodeException { 1049 1050 } 1051 1052 private void writeOutNewComponent(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw, Tag component) throws BytecodeException { 1053 1054 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , NEW_COMPONENT_IMPL_INSTANCE, null, new Type[]{Types.PAGE_EXCEPTION}, cw); 1055 BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,NEW_COMPONENT_IMPL_INSTANCE,writeLog(),suppressWSbeforeArg,output); 1056 Label methodBegin=new Label(); 1057 Label methodEnd=new Label(); 1058 1059 adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0); 1060 ExpressionUtil.visitLine(bc, component.getStart()); 1061 adapter.visitLabel(methodBegin); 1062 1063 1064 int comp=adapter.newLocal(Types.COMPONENT_IMPL); 1065 adapter.newInstance(Types.COMPONENT_IMPL); 1066 adapter.dup(); 1067 1068 Attribute attr; 1069 // ComponentPage 1070 adapter.visitVarInsn(Opcodes.ALOAD, 0); 1071 adapter.checkCast(Types.COMPONENT_PAGE); 1072 1073 // !!! also check CFMLScriptTransformer.addMetaData if you do any change here !!! 1074 1075 // Output 1076 attr = component.removeAttribute("output"); 1077 if(attr!=null) { 1078 ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); 1079 } 1080 else ASMConstants.NULL(adapter); 1081 1082 // synchronized 1083 attr = component.removeAttribute("synchronized"); 1084 if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_VALUE); 1085 else adapter.push(false); 1086 1087 // extends 1088 attr = component.removeAttribute("extends"); 1089 if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); 1090 else adapter.push(""); 1091 1092 // implements 1093 attr = component.removeAttribute("implements"); 1094 if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); 1095 else adapter.push(""); 1096 1097 // hint 1098 attr = component.removeAttribute("hint"); 1099 if(attr!=null) { 1100 Expression value = attr.getValue(); 1101 if(!(value instanceof Literal)){ 1102 value=LitString.toExprString("[runtime expression]"); 1103 } 1104 ExpressionUtil.writeOutSilent(value,bc, Expression.MODE_REF); 1105 } 1106 else adapter.push(""); 1107 1108 // dspName 1109 attr = component.removeAttribute("displayname"); 1110 if(attr==null) attr=component.getAttribute("display"); 1111 if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); 1112 else adapter.push(""); 1113 1114 // callpath 1115 adapter.visitVarInsn(Opcodes.ALOAD, 2); 1116 // relpath 1117 adapter.visitVarInsn(Opcodes.ILOAD, 3); 1118 1119 1120 // style 1121 attr = component.removeAttribute("style"); 1122 if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); 1123 else adapter.push(""); 1124 1125 // persistent 1126 attr = component.removeAttribute("persistent"); 1127 boolean persistent=false; 1128 if(attr!=null) { 1129 persistent=ASMUtil.toBoolean(attr,component.getStart()).booleanValue(); 1130 } 1131 1132 // persistent 1133 attr = component.removeAttribute("accessors"); 1134 boolean accessors=false; 1135 if(attr!=null) { 1136 accessors=ASMUtil.toBoolean(attr,component.getStart()).booleanValue(); 1137 } 1138 1139 adapter.push(persistent); 1140 adapter.push(accessors); 1141 //ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_VALUE); 1142 1143 //adapter.visitVarInsn(Opcodes.ALOAD, 4); 1144 createMetaDataStruct(bc,component.getAttributes(),component.getMetaData()); 1145 1146 adapter.invokeConstructor(Types.COMPONENT_IMPL, CONSTR_COMPONENT_IMPL); 1147 1148 adapter.storeLocal(comp); 1149 1150 //Component Impl(ComponentPage componentPage,boolean output, String extend, String hint, String dspName) 1151 1152 1153 // initComponent(pc,c); 1154 adapter.visitVarInsn(Opcodes.ALOAD, 0); 1155 adapter.loadArg(0); 1156 adapter.loadLocal(comp); 1157 adapter.invokeVirtual(Types.COMPONENT_PAGE, INIT_COMPONENT); 1158 1159 adapter.visitLabel(methodEnd); 1160 1161 // return component; 1162 adapter.loadLocal(comp); 1163 1164 adapter.returnValue(); 1165 //ExpressionUtil.visitLine(adapter, component.getEndLine()); 1166 adapter.endMethod(); 1167 1168 1169 } 1170 1171 private void writeOutNewInterface(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw, Tag interf) throws BytecodeException { 1172 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , NEW_INTERFACE_IMPL_INSTANCE, null, new Type[]{Types.PAGE_EXCEPTION}, cw); 1173 BytecodeContext bc=new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,NEW_INTERFACE_IMPL_INSTANCE,writeLog(),suppressWSbeforeArg,output); 1174 Label methodBegin=new Label(); 1175 Label methodEnd=new Label(); 1176 1177 1178 adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0); 1179 ExpressionUtil.visitLine(bc, interf.getStart()); 1180 adapter.visitLabel(methodBegin); 1181 1182 //ExpressionUtil.visitLine(adapter, interf.getStartLine()); 1183 1184 int comp=adapter.newLocal(Types.INTERFACE_IMPL); 1185 1186 1187 adapter.newInstance(Types.INTERFACE_IMPL); 1188 adapter.dup(); 1189 1190 1191 Attribute attr; 1192 // Interface Page 1193 adapter.visitVarInsn(Opcodes.ALOAD, 0); 1194 adapter.checkCast(Types.INTERFACE_PAGE); 1195 1196 // extened 1197 attr = interf.removeAttribute("extends"); 1198 if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); 1199 else adapter.push(""); 1200 1201 // hint 1202 attr = interf.removeAttribute("hint"); 1203 if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); 1204 else adapter.push(""); 1205 1206 // dspName 1207 attr = interf.removeAttribute("displayname"); 1208 if(attr==null) attr=interf.getAttribute("display"); 1209 if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),bc, Expression.MODE_REF); 1210 else adapter.push(""); 1211 1212 1213 // callpath 1214 adapter.visitVarInsn(Opcodes.ALOAD, 1); 1215 // relpath 1216 adapter.visitVarInsn(Opcodes.ILOAD, 2); 1217 1218 // interface udfs 1219 adapter.visitVarInsn(Opcodes.ALOAD, 3); 1220 1221 createMetaDataStruct(bc,interf.getAttributes(),interf.getMetaData()); 1222 1223 1224 adapter.invokeConstructor(Types.INTERFACE_IMPL, CONSTR_INTERFACE_IMPL); 1225 1226 adapter.storeLocal(comp); 1227 1228 1229 1230 // initInterface(pc,c); 1231 adapter.visitVarInsn(Opcodes.ALOAD, 0); 1232 //adapter.loadArg(0); 1233 adapter.loadLocal(comp); 1234 adapter.invokeVirtual(Types.INTERFACE_PAGE, INIT_INTERFACE); 1235 1236 adapter.visitLabel(methodEnd); 1237 1238 1239 // return interface; 1240 adapter.loadLocal(comp); 1241 1242 adapter.returnValue(); 1243 //ExpressionUtil.visitLine(adapter, interf.getEndLine()); 1244 adapter.endMethod(); 1245 1246 1247 } 1248 1249 public static boolean hasMetaDataStruct(Map attrs, Map meta) { 1250 if((attrs==null || attrs.size()==0) && (meta==null || meta.size()==0)){ 1251 return false; 1252 } 1253 return true; 1254 } 1255 1256 public static void createMetaDataStruct(BytecodeContext bc, Map attrs, Map meta) throws BytecodeException { 1257 1258 1259 GeneratorAdapter adapter = bc.getAdapter(); 1260 if((attrs==null || attrs.size()==0) && (meta==null || meta.size()==0)){ 1261 ASMConstants.NULL(bc.getAdapter()); 1262 bc.getAdapter().cast(Types.OBJECT,Types.STRUCT_IMPL); 1263 return; 1264 } 1265 1266 int sct=adapter.newLocal(Types.STRUCT_IMPL); 1267 adapter.newInstance(Types.STRUCT_IMPL); 1268 adapter.dup(); 1269 adapter.invokeConstructor(Types.STRUCT_IMPL, INIT_STRUCT_IMPL); 1270 adapter.storeLocal(sct); 1271 if(meta!=null) { 1272 _createMetaDataStruct(bc,adapter,sct,meta); 1273 } 1274 if(attrs!=null) { 1275 _createMetaDataStruct(bc,adapter,sct,attrs); 1276 } 1277 1278 1279 adapter.loadLocal(sct); 1280 } 1281 1282 private static void _createMetaDataStruct(BytecodeContext bc, GeneratorAdapter adapter, int sct, Map attrs) throws BytecodeException { 1283 Attribute attr; 1284 Iterator it = attrs.entrySet().iterator(); 1285 Entry entry; 1286 while(it.hasNext()){ 1287 entry = (Map.Entry)it.next(); 1288 attr=(Attribute) entry.getValue(); 1289 adapter.loadLocal(sct); 1290 adapter.push(attr.getName()); 1291 if(attr.getValue() instanceof Literal) 1292 ExpressionUtil.writeOutSilent(attr.getValue(),bc,Expression.MODE_REF); 1293 else 1294 adapter.push("[runtime expression]"); 1295 1296 adapter.invokeVirtual(Types.STRUCT_IMPL, SET_EL); 1297 adapter.pop(); 1298 } 1299 } 1300 1301 private void writeOutCall(BytecodeContext statConstr,BytecodeContext constr,List<LitString> keys,ClassWriter cw) throws BytecodeException { 1302 //GeneratorAdapter adapter = bc.getAdapter(); 1303 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , CALL, null, new Type[]{Types.THROWABLE}, cw); 1304 Label methodBegin=new Label(); 1305 Label methodEnd=new Label(); 1306 1307 adapter.visitLocalVariable("this", "L"+name+";", null, methodBegin, methodEnd, 0); 1308 adapter.visitLabel(methodBegin); 1309 1310 writeOutCallBody(new BytecodeContext(null,statConstr, constr,this,keys,cw,name,adapter,CALL,writeLog(),suppressWSbeforeArg,output),this,IFunction.PAGE_TYPE_REGULAR); 1311 1312 adapter.visitLabel(methodEnd); 1313 adapter.returnValue(); 1314 adapter.endMethod(); 1315 } 1316 1317 1318 private void writeOutCallBody(BytecodeContext bc,Body body, int pageType) throws BytecodeException { 1319 // Other 1320 List<IFunction> functions=new ArrayList<IFunction>(); 1321 getFunctions(functions,bc,body,pageType); 1322 1323 String className = Types.UDF_PROPERTIES_ARRAY.toString(); 1324 //FieldVisitor fv = bc.getClassWriter().visitField(Opcodes.ACC_PRIVATE , "udfs",className , null, null); 1325 //fv.visitEnd(); 1326 1327 BytecodeContext constr = bc.getConstructor(); 1328 GeneratorAdapter cga = constr.getAdapter(); 1329 1330 cga.visitVarInsn(Opcodes.ALOAD, 0); 1331 cga.push(functions.size()); 1332 //cga.visitTypeInsn(Opcodes.ANEWARRAY, Types.UDF_PROPERTIES.toString()); 1333 cga.newArray(Types.UDF_PROPERTIES); 1334 cga.visitFieldInsn(Opcodes.PUTFIELD, bc.getClassName(), "udfs", className); 1335 1336 1337 Iterator<IFunction> it = functions.iterator(); 1338 while(it.hasNext()){ 1339 it.next().writeOut(bc, pageType); 1340 } 1341 1342 if(pageType==IFunction.PAGE_TYPE_COMPONENT) { 1343 GeneratorAdapter adapter = bc.getAdapter(); 1344 adapter.loadArg(1); 1345 adapter.loadArg(0); 1346 adapter.visitVarInsn(Opcodes.ALOAD, 0); 1347 adapter.invokeVirtual(Types.COMPONENT_IMPL, CHECK_INTERFACE); 1348 1349 } 1350 if(pageType!=IFunction.PAGE_TYPE_INTERFACE){ 1351 //BodyBase.writeOut(bc.getStaticConstructor(),bc.getConstructor(),bc.getKeys(),body.getStatements(), bc); 1352 BodyBase.writeOut(bc,body); 1353 } 1354 } 1355 1356 private static void getImports(List<String> list,Body body) throws BytecodeException { 1357 if(ASMUtil.isEmpty(body)) return; 1358 Statement stat; 1359 List stats = body.getStatements(); 1360 int len=stats.size(); 1361 for(int i=0;i<len;i++) { 1362 stat = (Statement)stats.get(i); 1363 1364 // IFunction 1365 if(stat instanceof TagImport && !StringUtil.isEmpty(((TagImport)stat).getPath(),true)) { 1366 ImportDefintion id = ImportDefintionImpl.getInstance(((TagImport) stat).getPath(), null); 1367 if(id!=null && (!list.contains(id.toString()) && !list.contains(id.getPackage()+".*"))){ 1368 list.add(id.toString()); 1369 } 1370 stats.remove(i); 1371 len--; 1372 i--; 1373 1374 } 1375 else if(stat instanceof HasBody) getImports(list, ((HasBody)stat).getBody()); 1376 else if(stat instanceof HasBodies) { 1377 Body[] bodies=((HasBodies)stat).getBodies(); 1378 for(int y=0;y<bodies.length;y++) { 1379 getImports(list,bodies[y]); 1380 } 1381 } 1382 } 1383 } 1384 1385 1386 private static void getFunctions(List<IFunction> functions,BytecodeContext bc, Body body, int pageType) throws BytecodeException { 1387 //writeOutImports(bc, body, pageType); 1388 if(ASMUtil.isEmpty(body)) return; 1389 Statement stat; 1390 List stats = body.getStatements(); 1391 int len=stats.size(); 1392 for(int i=0;i<len;i++) { 1393 stat = (Statement)stats.get(i); 1394 1395 // IFunction 1396 if(stat instanceof IFunction) { 1397 functions.add((IFunction)stat); 1398 //((IFunction)stat).writeOut(bc,pageType); 1399 stats.remove(i); 1400 len--; 1401 i--; 1402 } 1403 else if(stat instanceof HasBody) getFunctions(functions,bc, ((HasBody)stat).getBody(), pageType); 1404 else if(stat instanceof HasBodies) { 1405 Body[] bodies=((HasBodies)stat).getBodies(); 1406 for(int y=0;y<bodies.length;y++) { 1407 getFunctions(functions,bc,bodies[y] , pageType); 1408 } 1409 1410 } 1411 } 1412 } 1413 1414 /** 1415 * @return if it is a component 1416 */ 1417 public boolean isComponent() { 1418 return isComponent; 1419 } 1420 1421 /** 1422 * set if the page is a component or not 1423 * @param cfc 1424 */ 1425 public void setIsComponent(boolean isComponent) { 1426 this.isComponent = isComponent; 1427 } 1428 1429 /** 1430 * @return if it is a component 1431 */ 1432 public boolean isInterface() { 1433 return isInterface; 1434 } 1435 1436 1437 public boolean isPage() { 1438 return !isInterface && !isComponent; 1439 } 1440 1441 /** 1442 * set if the page is a component or not 1443 * @param cfc 1444 */ 1445 public void setIsInterface(boolean isInterface) { 1446 this.isInterface = isInterface; 1447 } 1448 /** 1449 * @return the lastModifed 1450 */ 1451 public long getLastModifed() { 1452 return lastModifed; 1453 } 1454 1455 1456 public int[] addFunction(IFunction function) { 1457 int[] indexes=new int[2]; 1458 Iterator<IFunction> it = functions.iterator(); 1459 while(it.hasNext()){ 1460 if(it.next() instanceof FunctionImpl)indexes[IFunction.ARRAY_INDEX]++; 1461 } 1462 indexes[IFunction.VALUE_INDEX]=functions.size(); 1463 functions.add(function); 1464 return indexes; 1465 } 1466 1467 public int addThread(TagThread thread) { 1468 threads.add(thread); 1469 return threads.size()-1; 1470 } 1471 1472 public static byte[] setSourceLastModified(byte[] barr, long lastModified) { 1473 ClassReader cr = new ClassReader(barr); 1474 ClassWriter cw = ASMUtil.getClassWriter(); 1475 ClassVisitor ca = new SourceLastModifiedClassAdapter(cw,lastModified); 1476 cr.accept(ca, 0); 1477 return cw.toByteArray(); 1478 } 1479 1480 public Range registerString(BytecodeContext bc, String str) throws IOException { 1481 boolean append=true; 1482 1483 if(staticTextLocation==null) { 1484 PageSource ps = bc.getPageSource(); 1485 Mapping m = ps.getMapping(); 1486 staticTextLocation=m.getClassRootDirectory(); 1487 1488 staticTextLocation.mkdirs(); 1489 staticTextLocation=staticTextLocation.getRealResource(ps.getJavaName()+".txt"); 1490 if(staticTextLocation.exists()) append=false; 1491 else staticTextLocation.createFile(true); 1492 1493 off=0; 1494 } 1495 1496 1497 IOUtil.write(staticTextLocation, str, CharsetUtil.UTF8, append); 1498 Range r = new Range(off,str.length()); 1499 off+=str.length(); 1500 return r; 1501 } 1502 1503 public int getMethodCount() { 1504 return ++methodCount; 1505 } 1506 1507 public PageSource getPageSource() { 1508 return pageSource; 1509 } 1510 1511 public void setSplitIfNecessary(boolean splitIfNecessary) { 1512 this.splitIfNecessary=splitIfNecessary; 1513 } 1514 1515 public boolean getSplitIfNecessary() { 1516 return splitIfNecessary; 1517 } 1518 1519 1520 1521} 1522 class SourceLastModifiedClassAdapter extends ClassVisitor { 1523 1524 private long lastModified; 1525 public SourceLastModifiedClassAdapter(ClassWriter cw, long lastModified) { 1526 super(Opcodes.ASM4,cw); 1527 this.lastModified=lastModified; 1528 } 1529 public MethodVisitor visitMethod(int access,String name, String desc, String signature, String[] exceptions) { 1530 1531 if(!name.equals("getSourceLastModified"))return super.visitMethod(access,name, desc, signature, exceptions); 1532 1533 MethodVisitor mv = cv.visitMethod(access,name, desc, signature, exceptions); 1534 mv.visitCode(); 1535 mv.visitLdcInsn(Long.valueOf(lastModified)); 1536 mv.visitInsn(Opcodes.LRETURN); 1537 mv.visitEnd(); 1538 return mv; 1539 } 1540 1541 }