< prev index next >

src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/MethodGenerator.java

Print this page


   1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: MethodGenerator.java,v 1.2.4.1 2005/09/05 11:16:47 pvedula Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
  25 
  26 import java.util.ArrayList;
  27 import java.util.Collections;
  28 import java.util.HashMap;
  29 import java.util.Iterator;
  30 import java.util.Map;
  31 import java.util.Stack;
  32 
  33 
  34 import com.sun.org.apache.bcel.internal.Constants;
  35 import com.sun.org.apache.bcel.internal.classfile.Field;
  36 import com.sun.org.apache.bcel.internal.classfile.Method;
  37 import com.sun.org.apache.bcel.internal.generic.ALOAD;
  38 import com.sun.org.apache.bcel.internal.generic.ASTORE;
  39 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  40 import com.sun.org.apache.bcel.internal.generic.BranchInstruction;
  41 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  42 import com.sun.org.apache.bcel.internal.generic.DLOAD;
  43 import com.sun.org.apache.bcel.internal.generic.DSTORE;
  44 import com.sun.org.apache.bcel.internal.generic.FLOAD;
  45 import com.sun.org.apache.bcel.internal.generic.FSTORE;
  46 import com.sun.org.apache.bcel.internal.generic.GETFIELD;
  47 import com.sun.org.apache.bcel.internal.generic.GOTO;
  48 import com.sun.org.apache.bcel.internal.generic.ICONST;
  49 import com.sun.org.apache.bcel.internal.generic.IfInstruction;
  50 import com.sun.org.apache.bcel.internal.generic.ILOAD;
  51 import com.sun.org.apache.bcel.internal.generic.IndexedInstruction;
  52 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  53 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  54 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  55 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  56 import com.sun.org.apache.bcel.internal.generic.ISTORE;
  57 import com.sun.org.apache.bcel.internal.generic.Instruction;
  58 import com.sun.org.apache.bcel.internal.generic.InstructionConstants;
  59 import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  60 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  61 import com.sun.org.apache.bcel.internal.generic.InstructionTargeter;
  62 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  63 import com.sun.org.apache.bcel.internal.generic.LocalVariableInstruction;
  64 import com.sun.org.apache.bcel.internal.generic.LLOAD;
  65 import com.sun.org.apache.bcel.internal.generic.LSTORE;
  66 import com.sun.org.apache.bcel.internal.generic.MethodGen;
  67 import com.sun.org.apache.bcel.internal.generic.NEW;
  68 import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
  69 import com.sun.org.apache.bcel.internal.generic.RET;
  70 import com.sun.org.apache.bcel.internal.generic.Select;
  71 import com.sun.org.apache.bcel.internal.generic.TargetLostException;
  72 import com.sun.org.apache.bcel.internal.generic.Type;
  73 
  74 import com.sun.org.apache.xalan.internal.xsltc.compiler.Pattern;
  75 import com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC;
  76 
  77 /**
  78  * @author Jacek Ambroziak
  79  * @author Santiago Pericas-Geertsen
  80  */
  81 public class MethodGenerator extends MethodGen
  82     implements com.sun.org.apache.xalan.internal.xsltc.compiler.Constants {
  83     protected static final int INVALID_INDEX   = -1;
  84 
  85     private static final String START_ELEMENT_SIG
  86         = "(" + STRING_SIG + ")V";
  87     private static final String END_ELEMENT_SIG
  88         = START_ELEMENT_SIG;
  89 
  90     private InstructionList _mapTypeSub;
  91 
  92     private static final int DOM_INDEX       = 1;
  93     private static final int ITERATOR_INDEX  = 2;
  94     private static final int HANDLER_INDEX   = 3;
  95 
  96     private static final int MAX_METHOD_SIZE = 65535;
  97     private static final int MAX_BRANCH_TARGET_OFFSET = 32767;
  98     private static final int MIN_BRANCH_TARGET_OFFSET = -32768;
  99 
 100     private static final int TARGET_METHOD_SIZE = 60000;
 101     private static final int MINIMUM_OUTLINEABLE_CHUNK_SIZE = 1000;
 102 
 103     private Instruction       _iloadCurrent;
 104     private Instruction       _istoreCurrent;
 105     private final Instruction _astoreHandler;
 106     private final Instruction _aloadHandler;
 107     private final Instruction _astoreIterator;
 108     private final Instruction _aloadIterator;
 109     private final Instruction _aloadDom;
 110     private final Instruction _astoreDom;
 111 


1298         // InstructionLists for copying values into and out of an instance of
1299         // CopyLocals:
1300         //      oldMethCoypInIL  - from locals in old method into an instance
1301         //                         of the CopyLocals class (oldMethCopyInIL)
1302         //      oldMethCopyOutIL - from CopyLocals back into locals in the old
1303         //                         method
1304         //      newMethCopyInIL  - from CopyLocals into locals in the new
1305         //                         method
1306         //      newMethCopyOutIL - from locals in new method into the instance
1307         //                         of the CopyLocals class
1308         InstructionList oldMethCopyInIL  = new InstructionList();
1309         InstructionList oldMethCopyOutIL = new InstructionList();
1310         InstructionList newMethCopyInIL  = new InstructionList();
1311         InstructionList newMethCopyOutIL = new InstructionList();
1312 
1313         // Allocate instance of class in which we'll copy in or copy out locals
1314         // and make two copies:  last copy is used to invoke constructor;
1315         // other two are used for references to fields in the CopyLocals object
1316         InstructionHandle outlinedMethodCallSetup =
1317             oldMethCopyInIL.append(new NEW(cpg.addClass(argTypeName)));
1318         oldMethCopyInIL.append(InstructionConstants.DUP);
1319         oldMethCopyInIL.append(InstructionConstants.DUP);
1320         oldMethCopyInIL.append(
1321             new INVOKESPECIAL(cpg.addMethodref(argTypeName, "<init>", "()V")));
1322 
1323         // Generate code to invoke the new outlined method, and place the code
1324         // on oldMethCopyOutIL
1325         InstructionHandle outlinedMethodRef;
1326 
1327         if (isStaticMethod) {
1328             outlinedMethodRef =
1329                 oldMethCopyOutIL.append(
1330                     new INVOKESTATIC(cpg.addMethodref(
1331                                           classGen.getClassName(),
1332                                           outlinedMethodName,
1333                                           outlinedMethodGen.getSignature())));
1334         } else {
1335             oldMethCopyOutIL.append(InstructionConstants.THIS);
1336             oldMethCopyOutIL.append(InstructionConstants.SWAP);
1337             outlinedMethodRef =
1338                 oldMethCopyOutIL.append(
1339                     new INVOKEVIRTUAL(cpg.addMethodref(
1340                                           classGen.getClassName(),
1341                                           outlinedMethodName,
1342                                           outlinedMethodGen.getSignature())));
1343         }
1344 
1345         // Used to keep track of the first in a sequence of
1346         // OutlineableChunkStart instructions
1347         boolean chunkStartTargetMappingsPending = false;
1348         InstructionHandle pendingTargetMappingHandle = null;
1349 
1350         // Used to keep track of the last instruction that was copied
1351         InstructionHandle lastCopyHandle = null;
1352 
1353         // Keeps track of the mapping from instruction handles in the old
1354         // method to instruction handles in the outlined method.  Only need
1355         // to track instructions that are targeted by something else in the
1356         // generated BCEL


1462 
1463                             copyAreaFieldCount++;
1464                             String copyAreaFieldName =
1465                                            "field" + copyAreaFieldCount;
1466                             copyAreaCG.addField(
1467                                 new Field(ACC_PUBLIC,
1468                                         copyAreaCPG.addUtf8(copyAreaFieldName),
1469                                         copyAreaCPG.addUtf8(varSignature),
1470                                         null, copyAreaCPG.getConstantPool()));
1471 
1472                             int fieldRef = cpg.addFieldref(argTypeName,
1473                                                            copyAreaFieldName,
1474                                                            varSignature);
1475 
1476                             if (copyInLocalValue) {
1477                                 // Generate code for the old method to store the
1478                                 // value of the local into the correct field in
1479                                 // CopyLocals prior to invocation of the
1480                                 // outlined method.
1481                                 oldMethCopyInIL.append(
1482                                         InstructionConstants.DUP);
1483                                 InstructionHandle copyInLoad =
1484                                     oldMethCopyInIL.append(
1485                                         loadLocal(oldLocalVarIndex, varType));
1486                                 oldMethCopyInIL.append(new PUTFIELD(fieldRef));
1487 
1488                                 // If the end of the live range of the old
1489                                 // variable was in the middle of the outlined
1490                                 // chunk.  Make the load of its value the new
1491                                 // end of its range.
1492                                 if (!copyOutLocalValue) {
1493                                     revisedLocalVarEnd.put(oldLVG, copyInLoad);
1494                                 }
1495 
1496                                 // Generate code for start of the outlined
1497                                 // method to copy the value from a field in
1498                                 // CopyLocals to the new local in the outlined
1499                                 // method
1500                                 newMethCopyInIL.append(
1501                                         InstructionConstants.ALOAD_1);
1502                                 newMethCopyInIL.append(new GETFIELD(fieldRef));
1503                                 newMethCopyInIL.append(
1504                                         storeLocal(newLocalVarIndex, varType));
1505                             }
1506 
1507                             if (copyOutLocalValue) {
1508                                 // Generate code for the end of the outlined
1509                                 // method to copy the value from the new local
1510                                 // variable into a field in CopyLocals
1511                                 // method
1512                                 newMethCopyOutIL.append(
1513                                         InstructionConstants.ALOAD_1);
1514                                 newMethCopyOutIL.append(
1515                                         loadLocal(newLocalVarIndex, varType));
1516                                 newMethCopyOutIL.append(new PUTFIELD(fieldRef));
1517 
1518                                 // Generate code to copy the value from a field
1519                                 // in CopyLocals into a local in the original
1520                                 // method following invocation of the outlined
1521                                 // method.
1522                                 oldMethCopyOutIL.append(
1523                                         InstructionConstants.DUP);
1524                                 oldMethCopyOutIL.append(new GETFIELD(fieldRef));
1525                                 InstructionHandle copyOutStore =
1526                                     oldMethCopyOutIL.append(
1527                                         storeLocal(oldLocalVarIndex, varType));
1528 
1529                                 // If the start of the live range of the old
1530                                 // variable was in the middle of the outlined
1531                                 // chunk.  Make this store into it the new start
1532                                 // of its range.
1533                                 if (!copyInLocalValue) {
1534                                     revisedLocalVarStart.put(oldLVG,
1535                                                              copyOutStore);
1536                                 }
1537                             }
1538                         }
1539                     }
1540                 }
1541 
1542                 if (ih.hasTargeters()) {
1543                     targetMap.put(ih, lastCopyHandle);


1650                         Object newLVG = localVarMap.get(targeter);
1651                         if (newLVG != null) {
1652                             outlinedMethodGen.removeLocalVariable(
1653                                                   (LocalVariableGen)newLVG);
1654                         }
1655                     }
1656                 }
1657             }
1658 
1659             // If the current instruction in the original list was a marker,
1660             // it wasn't copied, so don't advance through the list of copied
1661             // instructions yet.
1662             if (!(i instanceof MarkerInstruction)) {
1663                 ch = ch.getNext();
1664             }
1665             ih = ih.getNext();
1666 
1667         }
1668 
1669         // POP the reference to the CopyLocals object from the stack
1670         oldMethCopyOutIL.append(InstructionConstants.POP);
1671 
1672         // Now that the generation of the outlined code is complete, update
1673         // the old local variables with new start and end ranges, as required.
1674         Iterator revisedLocalVarStartPairIter = revisedLocalVarStart.entrySet()
1675                                                                     .iterator();
1676         while (revisedLocalVarStartPairIter.hasNext()) {
1677             Map.Entry lvgRangeStartPair =
1678                     (Map.Entry)revisedLocalVarStartPairIter.next();
1679             LocalVariableGen lvg = (LocalVariableGen)lvgRangeStartPair.getKey();
1680             InstructionHandle startInst =
1681                     (InstructionHandle)lvgRangeStartPair.getValue();
1682 
1683             lvg.setStart(startInst);
1684 
1685         }
1686 
1687         Iterator revisedLocalVarEndPairIter = revisedLocalVarEnd.entrySet()
1688                                                                 .iterator();
1689         while (revisedLocalVarEndPairIter.hasNext()) {
1690             Map.Entry lvgRangeEndPair =
1691                     (Map.Entry)revisedLocalVarEndPairIter.next();
1692             LocalVariableGen lvg = (LocalVariableGen)lvgRangeEndPair.getKey();
1693             InstructionHandle endInst =
1694                     (InstructionHandle)lvgRangeEndPair.getValue();
1695 
1696             lvg.setEnd(endInst);
1697         }
1698 
1699         xsltc.dumpClass(copyAreaCG.getJavaClass());
1700 
1701         // Assemble the instruction lists so that the old method invokes the
1702         // new outlined method
1703         InstructionList oldMethodIL = getInstructionList();
1704 
1705         oldMethodIL.insert(first, oldMethCopyInIL);
1706         oldMethodIL.insert(first, oldMethCopyOutIL);
1707 
1708         // Insert the copying code into the outlined method
1709         newIL.insert(newMethCopyInIL);
1710         newIL.append(newMethCopyOutIL);
1711         newIL.append(InstructionConstants.RETURN);
1712 
1713         // Discard instructions in outlineable chunk from old method
1714         try {
1715             oldMethodIL.delete(first, last);
1716         } catch (TargetLostException e) {
1717             InstructionHandle[] targets = e.getTargets();
1718             // If there were still references to old instructions lingering,
1719             // clean those up.  The only instructions targetting the deleted
1720             // instructions should have been part of the chunk that was just
1721             // deleted, except that instructions might branch to the start of
1722             // the outlined chunk; similarly, all the live ranges of local
1723             // variables should have been adjusted, except for unreferenced
1724             // variables.
1725             for (int i = 0; i < targets.length; i++) {
1726                 InstructionHandle lostTarget = targets[i];
1727                 InstructionTargeter[] targeters = lostTarget.getTargeters();
1728                 for (int j = 0; j < targeters.length; j++) {
1729                     if (targeters[j] instanceof LocalVariableGen) {
1730                         LocalVariableGen lvgTargeter =
1731                                              (LocalVariableGen) targeters[j];


1982         InstructionList il = getInstructionList();
1983 
1984         // Loop through all the instructions, finding those that would be
1985         // affected by inserting new instructions in the InstructionList, and
1986         // calculating the maximum amount by which the relative offset between
1987         // two instructions could possibly change.
1988         // In part this loop duplicates code in
1989         // org.apache.bcel.generic.InstructionList.setPosition(), which does
1990         // this to determine whether to use 16-bit or 32-bit offsets for GOTO
1991         // and JSR instructions.  Ideally, that method would do the same for
1992         // conditional branch instructions, but it doesn't, so we duplicate the
1993         // processing here.
1994         for (InstructionHandle ih = il.getStart();
1995              ih != null;
1996              ih = ih.getNext()) {
1997             Instruction inst = ih.getInstruction();
1998 
1999             switch (inst.getOpcode()) {
2000                 // Instructions that may have 16-bit or 32-bit branch targets.
2001                 // The size of the branch offset might increase by two bytes.
2002                 case Constants.GOTO:
2003                 case Constants.JSR:
2004                     maxOffsetChange = maxOffsetChange + 2;
2005                     break;
2006                 // Instructions that contain padding for alignment purposes
2007                 // Up to three bytes of padding might be needed.  For greater
2008                 // accuracy, we should be able to discount any padding already
2009                 // added to these instructions by InstructionList.setPosition(),
2010                 // their APIs do not expose that information.
2011                 case Constants.TABLESWITCH:
2012                 case Constants.LOOKUPSWITCH:
2013                     maxOffsetChange = maxOffsetChange + 3;
2014                     break;
2015                 // Instructions that might be rewritten by this method as a
2016                 // conditional branch followed by an unconditional branch.
2017                 // The unconditional branch would require five bytes.
2018                 case Constants.IF_ACMPEQ:
2019                 case Constants.IF_ACMPNE:
2020                 case Constants.IF_ICMPEQ:
2021                 case Constants.IF_ICMPGE:
2022                 case Constants.IF_ICMPGT:
2023                 case Constants.IF_ICMPLE:
2024                 case Constants.IF_ICMPLT:
2025                 case Constants.IF_ICMPNE:
2026                 case Constants.IFEQ:
2027                 case Constants.IFGE:
2028                 case Constants.IFGT:
2029                 case Constants.IFLE:
2030                 case Constants.IFLT:
2031                 case Constants.IFNE:
2032                 case Constants.IFNONNULL:
2033                 case Constants.IFNULL:
2034                     maxOffsetChange = maxOffsetChange + 5;
2035                     break;
2036             }
2037         }
2038 
2039         // Now that the maximum number of bytes by which the method might grow
2040         // has been determined, look for conditional branches to see which
2041         // might possibly exceed the 16-bit relative offset.
2042         for (InstructionHandle ih = il.getStart();
2043              ih != null;
2044              ih = ih.getNext()) {
2045             Instruction inst = ih.getInstruction();
2046 
2047             if (inst instanceof IfInstruction) {
2048                 IfInstruction oldIfInst = (IfInstruction)inst;
2049                 BranchHandle oldIfHandle = (BranchHandle)ih;
2050                 InstructionHandle target = oldIfInst.getTarget();
2051                 int relativeTargetOffset = target.getPosition()
2052                                                - oldIfHandle.getPosition();
2053 


2060                              < MIN_BRANCH_TARGET_OFFSET)
2061                         || (relativeTargetOffset + maxOffsetChange
2062                                     > MAX_BRANCH_TARGET_OFFSET)) {
2063                     // Invert the logic of the IF instruction, and append
2064                     // that to the InstructionList following the original IF
2065                     // instruction
2066                     InstructionHandle nextHandle = oldIfHandle.getNext();
2067                     IfInstruction invertedIfInst = oldIfInst.negate();
2068                     BranchHandle invertedIfHandle = il.append(oldIfHandle,
2069                                                               invertedIfInst);
2070 
2071                     // Append an unconditional branch to the target of the
2072                     // original IF instruction after the new IF instruction
2073                     BranchHandle gotoHandle = il.append(invertedIfHandle,
2074                                                         new GOTO(target));
2075 
2076                     // If the original IF was the last instruction in
2077                     // InstructionList, add a new no-op to act as the target
2078                     // of the new IF
2079                     if (nextHandle == null) {
2080                         nextHandle = il.append(gotoHandle, NOP);
2081                     }
2082 
2083                     // Make the new IF instruction branch around the GOTO
2084                     invertedIfHandle.updateTarget(target, nextHandle);
2085 
2086                     // If anything still "points" to the old IF instruction,
2087                     // make adjustments to refer to either the new IF or GOTO
2088                     // instruction
2089                     if (oldIfHandle.hasTargeters()) {
2090                         InstructionTargeter[] targeters =
2091                                                   oldIfHandle.getTargeters();
2092 
2093                         for (int i = 0; i < targeters.length; i++) {
2094                             InstructionTargeter targeter = targeters[i];
2095                             // Ideally, one should simply be able to use
2096                             // InstructionTargeter.updateTarget to change
2097                             // references to the old IF instruction to the new
2098                             // IF instruction.  However, if a LocalVariableGen
2099                             // indicated the old IF marked the end of the range
2100                             // in which the IF variable is in use, the live


   1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: MethodGenerator.java,v 1.2.4.1 2005/09/05 11:16:47 pvedula Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
  25 
  26 import java.util.ArrayList;
  27 import java.util.Collections;
  28 import java.util.HashMap;
  29 import java.util.Iterator;
  30 import java.util.Map;
  31 import java.util.Stack;
  32 
  33 
  34 import com.sun.org.apache.bcel.internal.Const;
  35 import com.sun.org.apache.bcel.internal.classfile.Field;
  36 import com.sun.org.apache.bcel.internal.classfile.Method;
  37 import com.sun.org.apache.bcel.internal.generic.ALOAD;
  38 import com.sun.org.apache.bcel.internal.generic.ASTORE;
  39 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  40 import com.sun.org.apache.bcel.internal.generic.BranchInstruction;
  41 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  42 import com.sun.org.apache.bcel.internal.generic.DLOAD;
  43 import com.sun.org.apache.bcel.internal.generic.DSTORE;
  44 import com.sun.org.apache.bcel.internal.generic.FLOAD;
  45 import com.sun.org.apache.bcel.internal.generic.FSTORE;
  46 import com.sun.org.apache.bcel.internal.generic.GETFIELD;
  47 import com.sun.org.apache.bcel.internal.generic.GOTO;
  48 import com.sun.org.apache.bcel.internal.generic.ICONST;
  49 import com.sun.org.apache.bcel.internal.generic.IfInstruction;
  50 import com.sun.org.apache.bcel.internal.generic.ILOAD;
  51 import com.sun.org.apache.bcel.internal.generic.IndexedInstruction;
  52 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  53 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  54 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  55 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  56 import com.sun.org.apache.bcel.internal.generic.ISTORE;
  57 import com.sun.org.apache.bcel.internal.generic.Instruction;
  58 import com.sun.org.apache.bcel.internal.generic.InstructionConst;
  59 import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  60 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  61 import com.sun.org.apache.bcel.internal.generic.InstructionTargeter;
  62 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  63 import com.sun.org.apache.bcel.internal.generic.LocalVariableInstruction;
  64 import com.sun.org.apache.bcel.internal.generic.LLOAD;
  65 import com.sun.org.apache.bcel.internal.generic.LSTORE;
  66 import com.sun.org.apache.bcel.internal.generic.MethodGen;
  67 import com.sun.org.apache.bcel.internal.generic.NEW;
  68 import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
  69 import com.sun.org.apache.bcel.internal.generic.RET;
  70 import com.sun.org.apache.bcel.internal.generic.Select;
  71 import com.sun.org.apache.bcel.internal.generic.TargetLostException;
  72 import com.sun.org.apache.bcel.internal.generic.Type;
  73 
  74 import com.sun.org.apache.xalan.internal.xsltc.compiler.Pattern;
  75 import com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC;
  76 
  77 /**
  78  * @author Jacek Ambroziak
  79  * @author Santiago Pericas-Geertsen
  80  */
  81 public class MethodGenerator extends MethodGen
  82     implements com.sun.org.apache.xalan.internal.xsltc.compiler.Constants {
  83     protected static final int INVALID_INDEX   = -1;
  84 
  85     private static final String START_ELEMENT_SIG
  86         = "(" + STRING_SIG + ")V";
  87     private static final String END_ELEMENT_SIG
  88         = START_ELEMENT_SIG;
  89 


  90     private static final int DOM_INDEX       = 1;
  91     private static final int ITERATOR_INDEX  = 2;
  92     private static final int HANDLER_INDEX   = 3;
  93 
  94     private static final int MAX_METHOD_SIZE = 65535;
  95     private static final int MAX_BRANCH_TARGET_OFFSET = 32767;
  96     private static final int MIN_BRANCH_TARGET_OFFSET = -32768;
  97 
  98     private static final int TARGET_METHOD_SIZE = 60000;
  99     private static final int MINIMUM_OUTLINEABLE_CHUNK_SIZE = 1000;
 100 
 101     private Instruction       _iloadCurrent;
 102     private Instruction       _istoreCurrent;
 103     private final Instruction _astoreHandler;
 104     private final Instruction _aloadHandler;
 105     private final Instruction _astoreIterator;
 106     private final Instruction _aloadIterator;
 107     private final Instruction _aloadDom;
 108     private final Instruction _astoreDom;
 109 


1296         // InstructionLists for copying values into and out of an instance of
1297         // CopyLocals:
1298         //      oldMethCoypInIL  - from locals in old method into an instance
1299         //                         of the CopyLocals class (oldMethCopyInIL)
1300         //      oldMethCopyOutIL - from CopyLocals back into locals in the old
1301         //                         method
1302         //      newMethCopyInIL  - from CopyLocals into locals in the new
1303         //                         method
1304         //      newMethCopyOutIL - from locals in new method into the instance
1305         //                         of the CopyLocals class
1306         InstructionList oldMethCopyInIL  = new InstructionList();
1307         InstructionList oldMethCopyOutIL = new InstructionList();
1308         InstructionList newMethCopyInIL  = new InstructionList();
1309         InstructionList newMethCopyOutIL = new InstructionList();
1310 
1311         // Allocate instance of class in which we'll copy in or copy out locals
1312         // and make two copies:  last copy is used to invoke constructor;
1313         // other two are used for references to fields in the CopyLocals object
1314         InstructionHandle outlinedMethodCallSetup =
1315             oldMethCopyInIL.append(new NEW(cpg.addClass(argTypeName)));
1316         oldMethCopyInIL.append(InstructionConst.DUP);
1317         oldMethCopyInIL.append(InstructionConst.DUP);
1318         oldMethCopyInIL.append(
1319             new INVOKESPECIAL(cpg.addMethodref(argTypeName, "<init>", "()V")));
1320 
1321         // Generate code to invoke the new outlined method, and place the code
1322         // on oldMethCopyOutIL
1323         InstructionHandle outlinedMethodRef;
1324 
1325         if (isStaticMethod) {
1326             outlinedMethodRef =
1327                 oldMethCopyOutIL.append(
1328                     new INVOKESTATIC(cpg.addMethodref(
1329                                           classGen.getClassName(),
1330                                           outlinedMethodName,
1331                                           outlinedMethodGen.getSignature())));
1332         } else {
1333             oldMethCopyOutIL.append(InstructionConst.THIS);
1334             oldMethCopyOutIL.append(InstructionConst.SWAP);
1335             outlinedMethodRef =
1336                 oldMethCopyOutIL.append(
1337                     new INVOKEVIRTUAL(cpg.addMethodref(
1338                                           classGen.getClassName(),
1339                                           outlinedMethodName,
1340                                           outlinedMethodGen.getSignature())));
1341         }
1342 
1343         // Used to keep track of the first in a sequence of
1344         // OutlineableChunkStart instructions
1345         boolean chunkStartTargetMappingsPending = false;
1346         InstructionHandle pendingTargetMappingHandle = null;
1347 
1348         // Used to keep track of the last instruction that was copied
1349         InstructionHandle lastCopyHandle = null;
1350 
1351         // Keeps track of the mapping from instruction handles in the old
1352         // method to instruction handles in the outlined method.  Only need
1353         // to track instructions that are targeted by something else in the
1354         // generated BCEL


1460 
1461                             copyAreaFieldCount++;
1462                             String copyAreaFieldName =
1463                                            "field" + copyAreaFieldCount;
1464                             copyAreaCG.addField(
1465                                 new Field(ACC_PUBLIC,
1466                                         copyAreaCPG.addUtf8(copyAreaFieldName),
1467                                         copyAreaCPG.addUtf8(varSignature),
1468                                         null, copyAreaCPG.getConstantPool()));
1469 
1470                             int fieldRef = cpg.addFieldref(argTypeName,
1471                                                            copyAreaFieldName,
1472                                                            varSignature);
1473 
1474                             if (copyInLocalValue) {
1475                                 // Generate code for the old method to store the
1476                                 // value of the local into the correct field in
1477                                 // CopyLocals prior to invocation of the
1478                                 // outlined method.
1479                                 oldMethCopyInIL.append(
1480                                         InstructionConst.DUP);
1481                                 InstructionHandle copyInLoad =
1482                                     oldMethCopyInIL.append(
1483                                         loadLocal(oldLocalVarIndex, varType));
1484                                 oldMethCopyInIL.append(new PUTFIELD(fieldRef));
1485 
1486                                 // If the end of the live range of the old
1487                                 // variable was in the middle of the outlined
1488                                 // chunk.  Make the load of its value the new
1489                                 // end of its range.
1490                                 if (!copyOutLocalValue) {
1491                                     revisedLocalVarEnd.put(oldLVG, copyInLoad);
1492                                 }
1493 
1494                                 // Generate code for start of the outlined
1495                                 // method to copy the value from a field in
1496                                 // CopyLocals to the new local in the outlined
1497                                 // method
1498                                 newMethCopyInIL.append(
1499                                         InstructionConst.ALOAD_1);
1500                                 newMethCopyInIL.append(new GETFIELD(fieldRef));
1501                                 newMethCopyInIL.append(
1502                                         storeLocal(newLocalVarIndex, varType));
1503                             }
1504 
1505                             if (copyOutLocalValue) {
1506                                 // Generate code for the end of the outlined
1507                                 // method to copy the value from the new local
1508                                 // variable into a field in CopyLocals
1509                                 // method
1510                                 newMethCopyOutIL.append(
1511                                         InstructionConst.ALOAD_1);
1512                                 newMethCopyOutIL.append(
1513                                         loadLocal(newLocalVarIndex, varType));
1514                                 newMethCopyOutIL.append(new PUTFIELD(fieldRef));
1515 
1516                                 // Generate code to copy the value from a field
1517                                 // in CopyLocals into a local in the original
1518                                 // method following invocation of the outlined
1519                                 // method.
1520                                 oldMethCopyOutIL.append(
1521                                         InstructionConst.DUP);
1522                                 oldMethCopyOutIL.append(new GETFIELD(fieldRef));
1523                                 InstructionHandle copyOutStore =
1524                                     oldMethCopyOutIL.append(
1525                                         storeLocal(oldLocalVarIndex, varType));
1526 
1527                                 // If the start of the live range of the old
1528                                 // variable was in the middle of the outlined
1529                                 // chunk.  Make this store into it the new start
1530                                 // of its range.
1531                                 if (!copyInLocalValue) {
1532                                     revisedLocalVarStart.put(oldLVG,
1533                                                              copyOutStore);
1534                                 }
1535                             }
1536                         }
1537                     }
1538                 }
1539 
1540                 if (ih.hasTargeters()) {
1541                     targetMap.put(ih, lastCopyHandle);


1648                         Object newLVG = localVarMap.get(targeter);
1649                         if (newLVG != null) {
1650                             outlinedMethodGen.removeLocalVariable(
1651                                                   (LocalVariableGen)newLVG);
1652                         }
1653                     }
1654                 }
1655             }
1656 
1657             // If the current instruction in the original list was a marker,
1658             // it wasn't copied, so don't advance through the list of copied
1659             // instructions yet.
1660             if (!(i instanceof MarkerInstruction)) {
1661                 ch = ch.getNext();
1662             }
1663             ih = ih.getNext();
1664 
1665         }
1666 
1667         // POP the reference to the CopyLocals object from the stack
1668         oldMethCopyOutIL.append(InstructionConst.POP);
1669 
1670         // Now that the generation of the outlined code is complete, update
1671         // the old local variables with new start and end ranges, as required.
1672         Iterator revisedLocalVarStartPairIter = revisedLocalVarStart.entrySet()
1673                                                                     .iterator();
1674         while (revisedLocalVarStartPairIter.hasNext()) {
1675             Map.Entry lvgRangeStartPair =
1676                     (Map.Entry)revisedLocalVarStartPairIter.next();
1677             LocalVariableGen lvg = (LocalVariableGen)lvgRangeStartPair.getKey();
1678             InstructionHandle startInst =
1679                     (InstructionHandle)lvgRangeStartPair.getValue();
1680 
1681             lvg.setStart(startInst);
1682 
1683         }
1684 
1685         Iterator revisedLocalVarEndPairIter = revisedLocalVarEnd.entrySet()
1686                                                                 .iterator();
1687         while (revisedLocalVarEndPairIter.hasNext()) {
1688             Map.Entry lvgRangeEndPair =
1689                     (Map.Entry)revisedLocalVarEndPairIter.next();
1690             LocalVariableGen lvg = (LocalVariableGen)lvgRangeEndPair.getKey();
1691             InstructionHandle endInst =
1692                     (InstructionHandle)lvgRangeEndPair.getValue();
1693 
1694             lvg.setEnd(endInst);
1695         }
1696 
1697         xsltc.dumpClass(copyAreaCG.getJavaClass());
1698 
1699         // Assemble the instruction lists so that the old method invokes the
1700         // new outlined method
1701         InstructionList oldMethodIL = getInstructionList();
1702 
1703         oldMethodIL.insert(first, oldMethCopyInIL);
1704         oldMethodIL.insert(first, oldMethCopyOutIL);
1705 
1706         // Insert the copying code into the outlined method
1707         newIL.insert(newMethCopyInIL);
1708         newIL.append(newMethCopyOutIL);
1709         newIL.append(InstructionConst.RETURN);
1710 
1711         // Discard instructions in outlineable chunk from old method
1712         try {
1713             oldMethodIL.delete(first, last);
1714         } catch (TargetLostException e) {
1715             InstructionHandle[] targets = e.getTargets();
1716             // If there were still references to old instructions lingering,
1717             // clean those up.  The only instructions targetting the deleted
1718             // instructions should have been part of the chunk that was just
1719             // deleted, except that instructions might branch to the start of
1720             // the outlined chunk; similarly, all the live ranges of local
1721             // variables should have been adjusted, except for unreferenced
1722             // variables.
1723             for (int i = 0; i < targets.length; i++) {
1724                 InstructionHandle lostTarget = targets[i];
1725                 InstructionTargeter[] targeters = lostTarget.getTargeters();
1726                 for (int j = 0; j < targeters.length; j++) {
1727                     if (targeters[j] instanceof LocalVariableGen) {
1728                         LocalVariableGen lvgTargeter =
1729                                              (LocalVariableGen) targeters[j];


1980         InstructionList il = getInstructionList();
1981 
1982         // Loop through all the instructions, finding those that would be
1983         // affected by inserting new instructions in the InstructionList, and
1984         // calculating the maximum amount by which the relative offset between
1985         // two instructions could possibly change.
1986         // In part this loop duplicates code in
1987         // org.apache.bcel.generic.InstructionList.setPosition(), which does
1988         // this to determine whether to use 16-bit or 32-bit offsets for GOTO
1989         // and JSR instructions.  Ideally, that method would do the same for
1990         // conditional branch instructions, but it doesn't, so we duplicate the
1991         // processing here.
1992         for (InstructionHandle ih = il.getStart();
1993              ih != null;
1994              ih = ih.getNext()) {
1995             Instruction inst = ih.getInstruction();
1996 
1997             switch (inst.getOpcode()) {
1998                 // Instructions that may have 16-bit or 32-bit branch targets.
1999                 // The size of the branch offset might increase by two bytes.
2000                 case Const.GOTO:
2001                 case Const.JSR:
2002                     maxOffsetChange = maxOffsetChange + 2;
2003                     break;
2004                 // Instructions that contain padding for alignment purposes
2005                 // Up to three bytes of padding might be needed.  For greater
2006                 // accuracy, we should be able to discount any padding already
2007                 // added to these instructions by InstructionList.setPosition(),
2008                 // their APIs do not expose that information.
2009                 case Const.TABLESWITCH:
2010                 case Const.LOOKUPSWITCH:
2011                     maxOffsetChange = maxOffsetChange + 3;
2012                     break;
2013                 // Instructions that might be rewritten by this method as a
2014                 // conditional branch followed by an unconditional branch.
2015                 // The unconditional branch would require five bytes.
2016                 case Const.IF_ACMPEQ:
2017                 case Const.IF_ACMPNE:
2018                 case Const.IF_ICMPEQ:
2019                 case Const.IF_ICMPGE:
2020                 case Const.IF_ICMPGT:
2021                 case Const.IF_ICMPLE:
2022                 case Const.IF_ICMPLT:
2023                 case Const.IF_ICMPNE:
2024                 case Const.IFEQ:
2025                 case Const.IFGE:
2026                 case Const.IFGT:
2027                 case Const.IFLE:
2028                 case Const.IFLT:
2029                 case Const.IFNE:
2030                 case Const.IFNONNULL:
2031                 case Const.IFNULL:
2032                     maxOffsetChange = maxOffsetChange + 5;
2033                     break;
2034             }
2035         }
2036 
2037         // Now that the maximum number of bytes by which the method might grow
2038         // has been determined, look for conditional branches to see which
2039         // might possibly exceed the 16-bit relative offset.
2040         for (InstructionHandle ih = il.getStart();
2041              ih != null;
2042              ih = ih.getNext()) {
2043             Instruction inst = ih.getInstruction();
2044 
2045             if (inst instanceof IfInstruction) {
2046                 IfInstruction oldIfInst = (IfInstruction)inst;
2047                 BranchHandle oldIfHandle = (BranchHandle)ih;
2048                 InstructionHandle target = oldIfInst.getTarget();
2049                 int relativeTargetOffset = target.getPosition()
2050                                                - oldIfHandle.getPosition();
2051 


2058                              < MIN_BRANCH_TARGET_OFFSET)
2059                         || (relativeTargetOffset + maxOffsetChange
2060                                     > MAX_BRANCH_TARGET_OFFSET)) {
2061                     // Invert the logic of the IF instruction, and append
2062                     // that to the InstructionList following the original IF
2063                     // instruction
2064                     InstructionHandle nextHandle = oldIfHandle.getNext();
2065                     IfInstruction invertedIfInst = oldIfInst.negate();
2066                     BranchHandle invertedIfHandle = il.append(oldIfHandle,
2067                                                               invertedIfInst);
2068 
2069                     // Append an unconditional branch to the target of the
2070                     // original IF instruction after the new IF instruction
2071                     BranchHandle gotoHandle = il.append(invertedIfHandle,
2072                                                         new GOTO(target));
2073 
2074                     // If the original IF was the last instruction in
2075                     // InstructionList, add a new no-op to act as the target
2076                     // of the new IF
2077                     if (nextHandle == null) {
2078                         nextHandle = il.append(gotoHandle, InstructionConst.NOP);
2079                     }
2080 
2081                     // Make the new IF instruction branch around the GOTO
2082                     invertedIfHandle.updateTarget(target, nextHandle);
2083 
2084                     // If anything still "points" to the old IF instruction,
2085                     // make adjustments to refer to either the new IF or GOTO
2086                     // instruction
2087                     if (oldIfHandle.hasTargeters()) {
2088                         InstructionTargeter[] targeters =
2089                                                   oldIfHandle.getTargeters();
2090 
2091                         for (int i = 0; i < targeters.length; i++) {
2092                             InstructionTargeter targeter = targeters[i];
2093                             // Ideally, one should simply be able to use
2094                             // InstructionTargeter.updateTarget to change
2095                             // references to the old IF instruction to the new
2096                             // IF instruction.  However, if a LocalVariableGen
2097                             // indicated the old IF marked the end of the range
2098                             // in which the IF variable is in use, the live


< prev index next >