diff --git a/libs/spigot.jar b/libs/spigot.jar new file mode 100644 index 0000000..616b051 Binary files /dev/null and b/libs/spigot.jar differ diff --git a/src/com/cnaude/chairs/Chairs.java b/src/com/cnaude/chairs/Chairs.java index 9ca83ef..676d773 100644 --- a/src/com/cnaude/chairs/Chairs.java +++ b/src/com/cnaude/chairs/Chairs.java @@ -1,6 +1,9 @@ package com.cnaude.chairs; import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -12,9 +15,11 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Arrow; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; @@ -22,9 +27,6 @@ import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.util.Vector; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; - public class Chairs extends JavaPlugin { public ChairEffects chairEffects; public List allowedBlocks; @@ -42,11 +44,28 @@ public class Chairs extends JavaPlugin { public PluginManager pm; public ChairsIgnoreList ignoreList; public String msgSitting, msgStanding, msgOccupied, msgNoPerm, msgReloaded, msgDisabled, msgEnabled; - private ProtocolManager protocolManager; + + private Class vehiclearrowclass; @Override public void onEnable() { log = this.getLogger(); + try { + World world = getServer().getWorlds().get(0); + Arrow arrow = world.spawnArrow(new Location(world, 0, 0, 0), new Vector(0, 0, 0), 0, 0); + String arrowclass = arrow.getClass().getName(); + Method getHandle; + getHandle = arrow.getClass().getDeclaredMethod("getHandle"); + getHandle.setAccessible(true); + Class entityarrow = getHandle.invoke(arrow).getClass(); + Class craftserver = getServer().getClass(); + vehiclearrowclass = new GenVehicleArrowClass().genAndLoadClass(arrowclass, entityarrow, craftserver); + } catch (Exception e) { + e.printStackTrace(); + log.severe("Failed to generate VehicleArrow class, exiting"); + getServer().getPluginManager().disablePlugin(this); + return; + } ignoreList = new ChairsIgnoreList(this); ignoreList.load(); pm = this.getServer().getPluginManager(); @@ -59,14 +78,11 @@ public class Chairs extends JavaPlugin { logInfo("Enabling sitting effects."); chairEffects = new ChairEffects(this); } - protocolManager = ProtocolLibrary.getProtocolManager(); - new PacketListener(protocolManager, this); + } @Override public void onDisable() { - protocolManager.getAsynchronousManager().unregisterAsyncHandlers(this); - protocolManager = null; for (String pName : new HashSet(sit.keySet())) { ejectPlayerOnDisable(Bukkit.getPlayerExact(pName)); } @@ -93,21 +109,37 @@ public class Chairs extends JavaPlugin { protected HashMap sittask = new HashMap(); protected void sitPlayer(Player player, Location sitlocation) { - if (notifyplayer && !msgSitting.isEmpty()) { - player.sendMessage(msgSitting); - } - Block block = sitlocation.getBlock(); - sitstopteleportloc.put(player.getName(), player.getLocation()); - Entity arrow = block.getWorld().spawnArrow(block.getLocation().add(0.5, 0 , 0.5), new Vector(0, 0.1, 0), 0, 0); - player.teleport(sitlocation); - player.setSneaking(false); - arrow.setPassenger(player); - sit.put(player.getName(), arrow); - sitblock.put(block, player.getName()); - sitblockbr.put(player.getName(), block); - startReSitTask(player); - player.teleport(player.getWorld().getSpawnLocation()); + try { + if (notifyplayer && !msgSitting.isEmpty()) + { + player.sendMessage(msgSitting); + } + Block block = sitlocation.getBlock(); + sitstopteleportloc.put(player.getName(), player.getLocation()); + player.teleport(sitlocation); + player.setSneaking(false); + Location arrowloc = block.getLocation().add(0.5, 0 , 0.5); + Entity arrow = player.getWorld().spawnArrow(arrowloc, new Vector(0, 0.1 ,0), 0, 0); + Method getHandleMethod = arrow.getClass().getDeclaredMethod("getHandle"); + getHandleMethod.setAccessible(true); + Object nmsarrow = getHandleMethod.invoke(arrow); + Field bukkitEntityField = nmsarrow.getClass().getSuperclass().getDeclaredField("bukkitEntity"); + bukkitEntityField.setAccessible(true); + Constructor ctor = vehiclearrowclass.getDeclaredConstructor(this.getServer().getClass(), nmsarrow.getClass()); + ctor.setAccessible(true); + Object vehiclearrow = ctor.newInstance(this.getServer(), nmsarrow); + bukkitEntityField.set(nmsarrow, vehiclearrow); + arrow.setPassenger(player); + sit.put(player.getName(), (Entity) vehiclearrow); + sitblock.put(block, player.getName()); + sitblockbr.put(player.getName(), block); + startReSitTask(player); + player.teleport(player.getWorld().getSpawnLocation()); + } catch (Exception e) { + e.printStackTrace(); + } } + protected void startReSitTask(final Player player) { int task = @@ -122,19 +154,33 @@ public class Chairs extends JavaPlugin { } protected void reSitPlayer(final Player player) { - player.eject(); - final Entity prevarrow = sit.get(player.getName()); - Block block = sitblockbr.get(player.getName()); - final Entity arrow = block.getWorld().spawnArrow(block.getLocation().add(0.5, 0, 0.5), new Vector(0, 0.01, 0), 0, 0); - arrow.setPassenger(player); - sit.put(player.getName(), arrow); - Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() - { - public void run() + try { + player.eject(); + final Entity prevarrow = sit.get(player.getName()); + Block block = sitblockbr.get(player.getName()); + Location arrowloc = block.getLocation().add(0.5, 0 , 0.5); + Entity arrow = player.getWorld().spawnArrow(arrowloc, new Vector(0, 0.1 ,0), 0, 0); + Method getHandleMethod = arrow.getClass().getDeclaredMethod("getHandle"); + getHandleMethod.setAccessible(true); + Object nmsarrow = getHandleMethod.invoke(arrow); + Field bukkitEntityField = nmsarrow.getClass().getSuperclass().getDeclaredField("bukkitEntity"); + bukkitEntityField.setAccessible(true); + Constructor ctor = vehiclearrowclass.getDeclaredConstructor(this.getServer().getClass(), nmsarrow.getClass()); + ctor.setAccessible(true); + Object vehiclearrow = ctor.newInstance(this.getServer(), nmsarrow); + bukkitEntityField.set(nmsarrow, vehiclearrow); + arrow.setPassenger(player); + sit.put(player.getName(), arrow); + Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { - prevarrow.remove(); - } - },100); + public void run() + { + prevarrow.remove(); + } + },100); + } catch (Exception e) { + e.printStackTrace(); + } } protected void unSitPlayer(final Player player, boolean ignoretp) { @@ -241,7 +287,5 @@ public class Chairs extends JavaPlugin { public void logError(String _message) { log.log(Level.SEVERE, _message); } - - - + } diff --git a/src/com/cnaude/chairs/EventListener.java b/src/com/cnaude/chairs/EventListener.java index 2bd99fd..0db1477 100644 --- a/src/com/cnaude/chairs/EventListener.java +++ b/src/com/cnaude/chairs/EventListener.java @@ -16,6 +16,7 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.vehicle.VehicleExitEvent; import org.bukkit.material.Stairs; import org.bukkit.material.Step; import org.bukkit.material.WoodenStep; @@ -46,6 +47,20 @@ public class EventListener implements Listener { } } + @EventHandler + public void onExitVehicle(VehicleExitEvent e) + { + if (e.getVehicle().getPassenger() instanceof Player) + { + Player player = (Player) e.getVehicle().getPassenger(); + if (plugin.sit.containsKey(player.getName())) + { + e.setCancelled(true); + plugin.unSitPlayer(player, false); + } + } + } + @EventHandler(priority=EventPriority.HIGHEST,ignoreCancelled=true) public void onBlockBreak(BlockBreakEvent event) { diff --git a/src/com/cnaude/chairs/GenVehicleArrowClass.java b/src/com/cnaude/chairs/GenVehicleArrowClass.java new file mode 100644 index 0000000..b5af160 --- /dev/null +++ b/src/com/cnaude/chairs/GenVehicleArrowClass.java @@ -0,0 +1,90 @@ +package com.cnaude.chairs; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.ALOAD; +import org.apache.bcel.generic.ClassGen; +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.InstructionConstants; +import org.apache.bcel.generic.InstructionFactory; +import org.apache.bcel.generic.InstructionList; +import org.apache.bcel.generic.InvokeInstruction; +import org.apache.bcel.generic.MethodGen; +import org.apache.bcel.generic.Type; + +public class GenVehicleArrowClass { + + + public Class genAndLoadClass(String arrowclass, Class entityarrow, Class craftserver) throws IOException, ClassNotFoundException { + ClassGen cg = new ClassGen( + "VehicleArrow", + arrowclass, + "", + Constants.ACC_PUBLIC | Constants.ACC_SUPER, + new String[]{"org.bukkit.entity.Vehicle"} + ); + ConstantPoolGen cp = cg.getConstantPool(); + InstructionList il = new InstructionList(); + MethodGen mg = new MethodGen( + Constants.ACC_PUBLIC, + Type.VOID, + new Type[] { Type.getType(craftserver), Type.getType(entityarrow) }, + new String[] { "server", "entity" }, + "", + "VehicleArrow", + il, + cp + ); + InstructionFactory factory = new InstructionFactory(cg); + il.append(new ALOAD(0)); + il.append(new ALOAD(1)); + il.append(new ALOAD(2)); + InvokeInstruction ii = factory.createInvoke( + arrowclass, + "", + Type.VOID, + new Type[] {Type.getType(craftserver), Type.getType(entityarrow)}, + Constants.INVOKESPECIAL + ); + il.append(ii); + il.append(InstructionConstants.RETURN); + mg.setMaxStack(); + cg.addMethod(mg.getMethod()); + il.dispose(); + cg.getJavaClass().dump("VehicleArrow.class"); + File arrowfile = new File("VehicleArrow.class"); + InputStream arrwoinputstrean = new FileInputStream(arrowfile); + File jarfile = new File("VehicleArrow.jar"); + final ZipOutputStream zipout = new ZipOutputStream(new FileOutputStream(jarfile)); + ZipEntry entry = new ZipEntry(arrowfile.getName()); + zipout.putNextEntry(entry); + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = arrwoinputstrean.read(buffer)) != -1) { + zipout.write(buffer, 0, bytesRead); + } + zipout.closeEntry(); + arrwoinputstrean.close(); + zipout.close(); + URL url = jarfile.toURI().toURL(); + URL[] urls = new URL[]{url}; + URLClassLoader cl = new URLClassLoader(urls); + Class vehiclearrowclass = cl.loadClass("VehicleArrow"); + cl.close(); + arrowfile.delete(); + jarfile.delete(); + return vehiclearrowclass; + } + + + +} diff --git a/src/com/cnaude/chairs/PacketListener.java b/src/com/cnaude/chairs/PacketListener.java deleted file mode 100644 index bf13579..0000000 --- a/src/com/cnaude/chairs/PacketListener.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.cnaude.chairs; - -import org.bukkit.entity.Player; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolManager; -import com.comphenix.protocol.events.ListenerPriority; -import com.comphenix.protocol.events.PacketAdapter; -import com.comphenix.protocol.events.PacketEvent; - -public class PacketListener { - - private ProtocolManager pm; - private Chairs pluginInstance; - public PacketListener(ProtocolManager pm, Chairs plugin) - { - this.pm = pm; - this.pluginInstance = plugin; - playerDismountListener(); - } - - private void playerDismountListener() - { - pm.getAsynchronousManager().registerAsyncHandler( - new PacketAdapter(PacketAdapter - .params(pluginInstance, PacketType.Play.Client.STEER_VEHICLE) - .clientSide() - .listenerPriority(ListenerPriority.HIGHEST) - .optionIntercept() - ) - { - @Override - public void onPacketReceiving(final PacketEvent e) - { - if (!e.isCancelled()) - { - final Player player = e.getPlayer(); - if (e.getPacket().getBooleans().getValues().get(1)) - { - //just eject player if he is sitting on chair - if (pluginInstance.sit.containsKey(player.getName())) - { - pluginInstance.unSitPlayer(player,false); - } - } - } - } - }).syncStart(); - } - -} diff --git a/src/org/apache/bcel/Constants.java b/src/org/apache/bcel/Constants.java new file mode 100644 index 0000000..04e06ba --- /dev/null +++ b/src/org/apache/bcel/Constants.java @@ -0,0 +1,766 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel; + +/** + * Constants for the project, mostly defined in the JVM specification. + * + * @version $Id: Constants.java 410087 2006-05-29 12:12:19Z tcurdt $ + * @author M. Dahm + */ +public interface Constants { + /** Major and minor version of the code. + */ + public final static short MAJOR_1_1 = 45; + public final static short MINOR_1_1 = 3; + public final static short MAJOR_1_2 = 46; + public final static short MINOR_1_2 = 0; + public final static short MAJOR_1_3 = 47; + public final static short MINOR_1_3 = 0; + public final static short MAJOR_1_4 = 48; + public final static short MINOR_1_4 = 0; + public final static short MAJOR_1_5 = 49; + public final static short MINOR_1_5 = 0; + public final static short MAJOR = MAJOR_1_1; // Defaults + public final static short MINOR = MINOR_1_1; + + /** Maximum value for an unsigned short. + */ + public final static int MAX_SHORT = 65535; // 2^16 - 1 + + /** Maximum value for an unsigned byte. + */ + public final static int MAX_BYTE = 255; // 2^8 - 1 + + /** Access flags for classes, fields and methods. + */ + public final static short ACC_PUBLIC = 0x0001; + public final static short ACC_PRIVATE = 0x0002; + public final static short ACC_PROTECTED = 0x0004; + public final static short ACC_STATIC = 0x0008; + + public final static short ACC_FINAL = 0x0010; + public final static short ACC_SYNCHRONIZED = 0x0020; + public final static short ACC_VOLATILE = 0x0040; + public final static short ACC_BRIDGE = 0x0040; + public final static short ACC_TRANSIENT = 0x0080; + public final static short ACC_VARARGS = 0x0080; + + public final static short ACC_NATIVE = 0x0100; + public final static short ACC_INTERFACE = 0x0200; + public final static short ACC_ABSTRACT = 0x0400; + public final static short ACC_STRICT = 0x0800; + + public final static short ACC_SYNTHETIC = 0x1000; + public final static short ACC_ANNOTATION = 0x2000; + public final static short ACC_ENUM = 0x4000; + + // Applies to classes compiled by new compilers only + public final static short ACC_SUPER = 0x0020; + + public final static short MAX_ACC_FLAG = ACC_ENUM; + + public final static String[] ACCESS_NAMES = { + "public", "private", "protected", "static", "final", "synchronized", + "volatile", "transient", "native", "interface", "abstract", "strictfp", + "synthetic", "annotation", "enum" + }; + + /** Tags in constant pool to denote type of constant. + */ + public final static byte CONSTANT_Utf8 = 1; + public final static byte CONSTANT_Integer = 3; + public final static byte CONSTANT_Float = 4; + public final static byte CONSTANT_Long = 5; + public final static byte CONSTANT_Double = 6; + public final static byte CONSTANT_Class = 7; + public final static byte CONSTANT_Fieldref = 9; + public final static byte CONSTANT_String = 8; + public final static byte CONSTANT_Methodref = 10; + public final static byte CONSTANT_InterfaceMethodref = 11; + public final static byte CONSTANT_NameAndType = 12; + + public final static String[] CONSTANT_NAMES = { + "", "CONSTANT_Utf8", "", "CONSTANT_Integer", + "CONSTANT_Float", "CONSTANT_Long", "CONSTANT_Double", + "CONSTANT_Class", "CONSTANT_String", "CONSTANT_Fieldref", + "CONSTANT_Methodref", "CONSTANT_InterfaceMethodref", + "CONSTANT_NameAndType" }; + + /** The name of the static initializer, also called "class + * initialization method" or "interface initialization + * method". This is "<clinit>". + */ + public final static String STATIC_INITIALIZER_NAME = ""; + + /** The name of every constructor method in a class, also called + * "instance initialization method". This is "<init>". + */ + public final static String CONSTRUCTOR_NAME = ""; + + /** The names of the interfaces implemented by arrays */ + public final static String[] INTERFACES_IMPLEMENTED_BY_ARRAYS = {"java.lang.Cloneable", "java.io.Serializable"}; + + /** + * Limitations of the Java Virtual Machine. + * See The Java Virtual Machine Specification, Second Edition, page 152, chapter 4.10. + */ + public static final int MAX_CP_ENTRIES = 65535; + public static final int MAX_CODE_SIZE = 65536; //bytes + + /** Java VM opcodes. + */ + public static final short NOP = 0; + public static final short ACONST_NULL = 1; + public static final short ICONST_M1 = 2; + public static final short ICONST_0 = 3; + public static final short ICONST_1 = 4; + public static final short ICONST_2 = 5; + public static final short ICONST_3 = 6; + public static final short ICONST_4 = 7; + public static final short ICONST_5 = 8; + public static final short LCONST_0 = 9; + public static final short LCONST_1 = 10; + public static final short FCONST_0 = 11; + public static final short FCONST_1 = 12; + public static final short FCONST_2 = 13; + public static final short DCONST_0 = 14; + public static final short DCONST_1 = 15; + public static final short BIPUSH = 16; + public static final short SIPUSH = 17; + public static final short LDC = 18; + public static final short LDC_W = 19; + public static final short LDC2_W = 20; + public static final short ILOAD = 21; + public static final short LLOAD = 22; + public static final short FLOAD = 23; + public static final short DLOAD = 24; + public static final short ALOAD = 25; + public static final short ILOAD_0 = 26; + public static final short ILOAD_1 = 27; + public static final short ILOAD_2 = 28; + public static final short ILOAD_3 = 29; + public static final short LLOAD_0 = 30; + public static final short LLOAD_1 = 31; + public static final short LLOAD_2 = 32; + public static final short LLOAD_3 = 33; + public static final short FLOAD_0 = 34; + public static final short FLOAD_1 = 35; + public static final short FLOAD_2 = 36; + public static final short FLOAD_3 = 37; + public static final short DLOAD_0 = 38; + public static final short DLOAD_1 = 39; + public static final short DLOAD_2 = 40; + public static final short DLOAD_3 = 41; + public static final short ALOAD_0 = 42; + public static final short ALOAD_1 = 43; + public static final short ALOAD_2 = 44; + public static final short ALOAD_3 = 45; + public static final short IALOAD = 46; + public static final short LALOAD = 47; + public static final short FALOAD = 48; + public static final short DALOAD = 49; + public static final short AALOAD = 50; + public static final short BALOAD = 51; + public static final short CALOAD = 52; + public static final short SALOAD = 53; + public static final short ISTORE = 54; + public static final short LSTORE = 55; + public static final short FSTORE = 56; + public static final short DSTORE = 57; + public static final short ASTORE = 58; + public static final short ISTORE_0 = 59; + public static final short ISTORE_1 = 60; + public static final short ISTORE_2 = 61; + public static final short ISTORE_3 = 62; + public static final short LSTORE_0 = 63; + public static final short LSTORE_1 = 64; + public static final short LSTORE_2 = 65; + public static final short LSTORE_3 = 66; + public static final short FSTORE_0 = 67; + public static final short FSTORE_1 = 68; + public static final short FSTORE_2 = 69; + public static final short FSTORE_3 = 70; + public static final short DSTORE_0 = 71; + public static final short DSTORE_1 = 72; + public static final short DSTORE_2 = 73; + public static final short DSTORE_3 = 74; + public static final short ASTORE_0 = 75; + public static final short ASTORE_1 = 76; + public static final short ASTORE_2 = 77; + public static final short ASTORE_3 = 78; + public static final short IASTORE = 79; + public static final short LASTORE = 80; + public static final short FASTORE = 81; + public static final short DASTORE = 82; + public static final short AASTORE = 83; + public static final short BASTORE = 84; + public static final short CASTORE = 85; + public static final short SASTORE = 86; + public static final short POP = 87; + public static final short POP2 = 88; + public static final short DUP = 89; + public static final short DUP_X1 = 90; + public static final short DUP_X2 = 91; + public static final short DUP2 = 92; + public static final short DUP2_X1 = 93; + public static final short DUP2_X2 = 94; + public static final short SWAP = 95; + public static final short IADD = 96; + public static final short LADD = 97; + public static final short FADD = 98; + public static final short DADD = 99; + public static final short ISUB = 100; + public static final short LSUB = 101; + public static final short FSUB = 102; + public static final short DSUB = 103; + public static final short IMUL = 104; + public static final short LMUL = 105; + public static final short FMUL = 106; + public static final short DMUL = 107; + public static final short IDIV = 108; + public static final short LDIV = 109; + public static final short FDIV = 110; + public static final short DDIV = 111; + public static final short IREM = 112; + public static final short LREM = 113; + public static final short FREM = 114; + public static final short DREM = 115; + public static final short INEG = 116; + public static final short LNEG = 117; + public static final short FNEG = 118; + public static final short DNEG = 119; + public static final short ISHL = 120; + public static final short LSHL = 121; + public static final short ISHR = 122; + public static final short LSHR = 123; + public static final short IUSHR = 124; + public static final short LUSHR = 125; + public static final short IAND = 126; + public static final short LAND = 127; + public static final short IOR = 128; + public static final short LOR = 129; + public static final short IXOR = 130; + public static final short LXOR = 131; + public static final short IINC = 132; + public static final short I2L = 133; + public static final short I2F = 134; + public static final short I2D = 135; + public static final short L2I = 136; + public static final short L2F = 137; + public static final short L2D = 138; + public static final short F2I = 139; + public static final short F2L = 140; + public static final short F2D = 141; + public static final short D2I = 142; + public static final short D2L = 143; + public static final short D2F = 144; + public static final short I2B = 145; + public static final short INT2BYTE = 145; // Old notion + public static final short I2C = 146; + public static final short INT2CHAR = 146; // Old notion + public static final short I2S = 147; + public static final short INT2SHORT = 147; // Old notion + public static final short LCMP = 148; + public static final short FCMPL = 149; + public static final short FCMPG = 150; + public static final short DCMPL = 151; + public static final short DCMPG = 152; + public static final short IFEQ = 153; + public static final short IFNE = 154; + public static final short IFLT = 155; + public static final short IFGE = 156; + public static final short IFGT = 157; + public static final short IFLE = 158; + public static final short IF_ICMPEQ = 159; + public static final short IF_ICMPNE = 160; + public static final short IF_ICMPLT = 161; + public static final short IF_ICMPGE = 162; + public static final short IF_ICMPGT = 163; + public static final short IF_ICMPLE = 164; + public static final short IF_ACMPEQ = 165; + public static final short IF_ACMPNE = 166; + public static final short GOTO = 167; + public static final short JSR = 168; + public static final short RET = 169; + public static final short TABLESWITCH = 170; + public static final short LOOKUPSWITCH = 171; + public static final short IRETURN = 172; + public static final short LRETURN = 173; + public static final short FRETURN = 174; + public static final short DRETURN = 175; + public static final short ARETURN = 176; + public static final short RETURN = 177; + public static final short GETSTATIC = 178; + public static final short PUTSTATIC = 179; + public static final short GETFIELD = 180; + public static final short PUTFIELD = 181; + public static final short INVOKEVIRTUAL = 182; + public static final short INVOKESPECIAL = 183; + public static final short INVOKENONVIRTUAL = 183; // Old name in JDK 1.0 + public static final short INVOKESTATIC = 184; + public static final short INVOKEINTERFACE = 185; + public static final short NEW = 187; + public static final short NEWARRAY = 188; + public static final short ANEWARRAY = 189; + public static final short ARRAYLENGTH = 190; + public static final short ATHROW = 191; + public static final short CHECKCAST = 192; + public static final short INSTANCEOF = 193; + public static final short MONITORENTER = 194; + public static final short MONITOREXIT = 195; + public static final short WIDE = 196; + public static final short MULTIANEWARRAY = 197; + public static final short IFNULL = 198; + public static final short IFNONNULL = 199; + public static final short GOTO_W = 200; + public static final short JSR_W = 201; + + /** + * Non-legal opcodes, may be used by JVM internally. + */ + public static final short BREAKPOINT = 202; + public static final short LDC_QUICK = 203; + public static final short LDC_W_QUICK = 204; + public static final short LDC2_W_QUICK = 205; + public static final short GETFIELD_QUICK = 206; + public static final short PUTFIELD_QUICK = 207; + public static final short GETFIELD2_QUICK = 208; + public static final short PUTFIELD2_QUICK = 209; + public static final short GETSTATIC_QUICK = 210; + public static final short PUTSTATIC_QUICK = 211; + public static final short GETSTATIC2_QUICK = 212; + public static final short PUTSTATIC2_QUICK = 213; + public static final short INVOKEVIRTUAL_QUICK = 214; + public static final short INVOKENONVIRTUAL_QUICK = 215; + public static final short INVOKESUPER_QUICK = 216; + public static final short INVOKESTATIC_QUICK = 217; + public static final short INVOKEINTERFACE_QUICK = 218; + public static final short INVOKEVIRTUALOBJECT_QUICK = 219; + public static final short NEW_QUICK = 221; + public static final short ANEWARRAY_QUICK = 222; + public static final short MULTIANEWARRAY_QUICK = 223; + public static final short CHECKCAST_QUICK = 224; + public static final short INSTANCEOF_QUICK = 225; + public static final short INVOKEVIRTUAL_QUICK_W = 226; + public static final short GETFIELD_QUICK_W = 227; + public static final short PUTFIELD_QUICK_W = 228; + public static final short IMPDEP1 = 254; + public static final short IMPDEP2 = 255; + + /** + * For internal purposes only. + */ + public static final short PUSH = 4711; + public static final short SWITCH = 4712; + + /** + * Illegal codes + */ + public static final short UNDEFINED = -1; + public static final short UNPREDICTABLE = -2; + public static final short RESERVED = -3; + public static final String ILLEGAL_OPCODE = ""; + public static final String ILLEGAL_TYPE = ""; + + public static final byte T_BOOLEAN = 4; + public static final byte T_CHAR = 5; + public static final byte T_FLOAT = 6; + public static final byte T_DOUBLE = 7; + public static final byte T_BYTE = 8; + public static final byte T_SHORT = 9; + public static final byte T_INT = 10; + public static final byte T_LONG = 11; + + public static final byte T_VOID = 12; // Non-standard + public static final byte T_ARRAY = 13; + public static final byte T_OBJECT = 14; + public static final byte T_REFERENCE = 14; // Deprecated + public static final byte T_UNKNOWN = 15; + public static final byte T_ADDRESS = 16; + + /** The primitive type names corresponding to the T_XX constants, + * e.g., TYPE_NAMES[T_INT] = "int" + */ + public static final String[] TYPE_NAMES = { + ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, + "boolean", "char", "float", "double", "byte", "short", "int", "long", + "void", "array", "object", "unknown" // Non-standard + }; + + /** The primitive class names corresponding to the T_XX constants, + * e.g., CLASS_TYPE_NAMES[T_INT] = "java.lang.Integer" + */ + public static final String[] CLASS_TYPE_NAMES = { + ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, + "java.lang.Boolean", "java.lang.Character", "java.lang.Float", + "java.lang.Double", "java.lang.Byte", "java.lang.Short", + "java.lang.Integer", "java.lang.Long", "java.lang.Void", + ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE + }; + + /** The signature characters corresponding to primitive types, + * e.g., SHORT_TYPE_NAMES[T_INT] = "I" + */ + public static final String[] SHORT_TYPE_NAMES = { + ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, + "Z", "C", "F", "D", "B", "S", "I", "J", + "V", ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE + }; + + /** + * Number of byte code operands, i.e., number of bytes after the tag byte + * itself. + */ + public static final short[] NO_OF_OPERANDS = { + 0/*nop*/, 0/*aconst_null*/, 0/*iconst_m1*/, 0/*iconst_0*/, + 0/*iconst_1*/, 0/*iconst_2*/, 0/*iconst_3*/, 0/*iconst_4*/, + 0/*iconst_5*/, 0/*lconst_0*/, 0/*lconst_1*/, 0/*fconst_0*/, + 0/*fconst_1*/, 0/*fconst_2*/, 0/*dconst_0*/, 0/*dconst_1*/, + 1/*bipush*/, 2/*sipush*/, 1/*ldc*/, 2/*ldc_w*/, 2/*ldc2_w*/, + 1/*iload*/, 1/*lload*/, 1/*fload*/, 1/*dload*/, 1/*aload*/, + 0/*iload_0*/, 0/*iload_1*/, 0/*iload_2*/, 0/*iload_3*/, + 0/*lload_0*/, 0/*lload_1*/, 0/*lload_2*/, 0/*lload_3*/, + 0/*fload_0*/, 0/*fload_1*/, 0/*fload_2*/, 0/*fload_3*/, + 0/*dload_0*/, 0/*dload_1*/, 0/*dload_2*/, 0/*dload_3*/, + 0/*aload_0*/, 0/*aload_1*/, 0/*aload_2*/, 0/*aload_3*/, + 0/*iaload*/, 0/*laload*/, 0/*faload*/, 0/*daload*/, + 0/*aaload*/, 0/*baload*/, 0/*caload*/, 0/*saload*/, + 1/*istore*/, 1/*lstore*/, 1/*fstore*/, 1/*dstore*/, + 1/*astore*/, 0/*istore_0*/, 0/*istore_1*/, 0/*istore_2*/, + 0/*istore_3*/, 0/*lstore_0*/, 0/*lstore_1*/, 0/*lstore_2*/, + 0/*lstore_3*/, 0/*fstore_0*/, 0/*fstore_1*/, 0/*fstore_2*/, + 0/*fstore_3*/, 0/*dstore_0*/, 0/*dstore_1*/, 0/*dstore_2*/, + 0/*dstore_3*/, 0/*astore_0*/, 0/*astore_1*/, 0/*astore_2*/, + 0/*astore_3*/, 0/*iastore*/, 0/*lastore*/, 0/*fastore*/, + 0/*dastore*/, 0/*aastore*/, 0/*bastore*/, 0/*castore*/, + 0/*sastore*/, 0/*pop*/, 0/*pop2*/, 0/*dup*/, 0/*dup_x1*/, + 0/*dup_x2*/, 0/*dup2*/, 0/*dup2_x1*/, 0/*dup2_x2*/, 0/*swap*/, + 0/*iadd*/, 0/*ladd*/, 0/*fadd*/, 0/*dadd*/, 0/*isub*/, + 0/*lsub*/, 0/*fsub*/, 0/*dsub*/, 0/*imul*/, 0/*lmul*/, + 0/*fmul*/, 0/*dmul*/, 0/*idiv*/, 0/*ldiv*/, 0/*fdiv*/, + 0/*ddiv*/, 0/*irem*/, 0/*lrem*/, 0/*frem*/, 0/*drem*/, + 0/*ineg*/, 0/*lneg*/, 0/*fneg*/, 0/*dneg*/, 0/*ishl*/, + 0/*lshl*/, 0/*ishr*/, 0/*lshr*/, 0/*iushr*/, 0/*lushr*/, + 0/*iand*/, 0/*land*/, 0/*ior*/, 0/*lor*/, 0/*ixor*/, 0/*lxor*/, + 2/*iinc*/, 0/*i2l*/, 0/*i2f*/, 0/*i2d*/, 0/*l2i*/, 0/*l2f*/, + 0/*l2d*/, 0/*f2i*/, 0/*f2l*/, 0/*f2d*/, 0/*d2i*/, 0/*d2l*/, + 0/*d2f*/, 0/*i2b*/, 0/*i2c*/, 0/*i2s*/, 0/*lcmp*/, 0/*fcmpl*/, + 0/*fcmpg*/, 0/*dcmpl*/, 0/*dcmpg*/, 2/*ifeq*/, 2/*ifne*/, + 2/*iflt*/, 2/*ifge*/, 2/*ifgt*/, 2/*ifle*/, 2/*if_icmpeq*/, + 2/*if_icmpne*/, 2/*if_icmplt*/, 2/*if_icmpge*/, 2/*if_icmpgt*/, + 2/*if_icmple*/, 2/*if_acmpeq*/, 2/*if_acmpne*/, 2/*goto*/, + 2/*jsr*/, 1/*ret*/, UNPREDICTABLE/*tableswitch*/, UNPREDICTABLE/*lookupswitch*/, + 0/*ireturn*/, 0/*lreturn*/, 0/*freturn*/, + 0/*dreturn*/, 0/*areturn*/, 0/*return*/, + 2/*getstatic*/, 2/*putstatic*/, 2/*getfield*/, + 2/*putfield*/, 2/*invokevirtual*/, 2/*invokespecial*/, 2/*invokestatic*/, + 4/*invokeinterface*/, UNDEFINED, 2/*new*/, + 1/*newarray*/, 2/*anewarray*/, + 0/*arraylength*/, 0/*athrow*/, 2/*checkcast*/, + 2/*instanceof*/, 0/*monitorenter*/, + 0/*monitorexit*/, UNPREDICTABLE/*wide*/, 3/*multianewarray*/, + 2/*ifnull*/, 2/*ifnonnull*/, 4/*goto_w*/, + 4/*jsr_w*/, 0/*breakpoint*/, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, RESERVED/*impdep1*/, RESERVED/*impdep2*/ + }; + + /** + * How the byte code operands are to be interpreted. + */ + public static final short[][] TYPE_OF_OPERANDS = { + {}/*nop*/, {}/*aconst_null*/, {}/*iconst_m1*/, {}/*iconst_0*/, + {}/*iconst_1*/, {}/*iconst_2*/, {}/*iconst_3*/, {}/*iconst_4*/, + {}/*iconst_5*/, {}/*lconst_0*/, {}/*lconst_1*/, {}/*fconst_0*/, + {}/*fconst_1*/, {}/*fconst_2*/, {}/*dconst_0*/, {}/*dconst_1*/, + {T_BYTE}/*bipush*/, {T_SHORT}/*sipush*/, {T_BYTE}/*ldc*/, + {T_SHORT}/*ldc_w*/, {T_SHORT}/*ldc2_w*/, + {T_BYTE}/*iload*/, {T_BYTE}/*lload*/, {T_BYTE}/*fload*/, + {T_BYTE}/*dload*/, {T_BYTE}/*aload*/, {}/*iload_0*/, + {}/*iload_1*/, {}/*iload_2*/, {}/*iload_3*/, {}/*lload_0*/, + {}/*lload_1*/, {}/*lload_2*/, {}/*lload_3*/, {}/*fload_0*/, + {}/*fload_1*/, {}/*fload_2*/, {}/*fload_3*/, {}/*dload_0*/, + {}/*dload_1*/, {}/*dload_2*/, {}/*dload_3*/, {}/*aload_0*/, + {}/*aload_1*/, {}/*aload_2*/, {}/*aload_3*/, {}/*iaload*/, + {}/*laload*/, {}/*faload*/, {}/*daload*/, {}/*aaload*/, + {}/*baload*/, {}/*caload*/, {}/*saload*/, {T_BYTE}/*istore*/, + {T_BYTE}/*lstore*/, {T_BYTE}/*fstore*/, {T_BYTE}/*dstore*/, + {T_BYTE}/*astore*/, {}/*istore_0*/, {}/*istore_1*/, + {}/*istore_2*/, {}/*istore_3*/, {}/*lstore_0*/, {}/*lstore_1*/, + {}/*lstore_2*/, {}/*lstore_3*/, {}/*fstore_0*/, {}/*fstore_1*/, + {}/*fstore_2*/, {}/*fstore_3*/, {}/*dstore_0*/, {}/*dstore_1*/, + {}/*dstore_2*/, {}/*dstore_3*/, {}/*astore_0*/, {}/*astore_1*/, + {}/*astore_2*/, {}/*astore_3*/, {}/*iastore*/, {}/*lastore*/, + {}/*fastore*/, {}/*dastore*/, {}/*aastore*/, {}/*bastore*/, + {}/*castore*/, {}/*sastore*/, {}/*pop*/, {}/*pop2*/, {}/*dup*/, + {}/*dup_x1*/, {}/*dup_x2*/, {}/*dup2*/, {}/*dup2_x1*/, + {}/*dup2_x2*/, {}/*swap*/, {}/*iadd*/, {}/*ladd*/, {}/*fadd*/, + {}/*dadd*/, {}/*isub*/, {}/*lsub*/, {}/*fsub*/, {}/*dsub*/, + {}/*imul*/, {}/*lmul*/, {}/*fmul*/, {}/*dmul*/, {}/*idiv*/, + {}/*ldiv*/, {}/*fdiv*/, {}/*ddiv*/, {}/*irem*/, {}/*lrem*/, + {}/*frem*/, {}/*drem*/, {}/*ineg*/, {}/*lneg*/, {}/*fneg*/, + {}/*dneg*/, {}/*ishl*/, {}/*lshl*/, {}/*ishr*/, {}/*lshr*/, + {}/*iushr*/, {}/*lushr*/, {}/*iand*/, {}/*land*/, {}/*ior*/, + {}/*lor*/, {}/*ixor*/, {}/*lxor*/, {T_BYTE, T_BYTE}/*iinc*/, + {}/*i2l*/, {}/*i2f*/, {}/*i2d*/, {}/*l2i*/, {}/*l2f*/, {}/*l2d*/, + {}/*f2i*/, {}/*f2l*/, {}/*f2d*/, {}/*d2i*/, {}/*d2l*/, {}/*d2f*/, + {}/*i2b*/, {}/*i2c*/,{}/*i2s*/, {}/*lcmp*/, {}/*fcmpl*/, + {}/*fcmpg*/, {}/*dcmpl*/, {}/*dcmpg*/, {T_SHORT}/*ifeq*/, + {T_SHORT}/*ifne*/, {T_SHORT}/*iflt*/, {T_SHORT}/*ifge*/, + {T_SHORT}/*ifgt*/, {T_SHORT}/*ifle*/, {T_SHORT}/*if_icmpeq*/, + {T_SHORT}/*if_icmpne*/, {T_SHORT}/*if_icmplt*/, + {T_SHORT}/*if_icmpge*/, {T_SHORT}/*if_icmpgt*/, + {T_SHORT}/*if_icmple*/, {T_SHORT}/*if_acmpeq*/, + {T_SHORT}/*if_acmpne*/, {T_SHORT}/*goto*/, {T_SHORT}/*jsr*/, + {T_BYTE}/*ret*/, {}/*tableswitch*/, {}/*lookupswitch*/, + {}/*ireturn*/, {}/*lreturn*/, {}/*freturn*/, {}/*dreturn*/, + {}/*areturn*/, {}/*return*/, {T_SHORT}/*getstatic*/, + {T_SHORT}/*putstatic*/, {T_SHORT}/*getfield*/, + {T_SHORT}/*putfield*/, {T_SHORT}/*invokevirtual*/, + {T_SHORT}/*invokespecial*/, {T_SHORT}/*invokestatic*/, + {T_SHORT, T_BYTE, T_BYTE}/*invokeinterface*/, {}, + {T_SHORT}/*new*/, {T_BYTE}/*newarray*/, + {T_SHORT}/*anewarray*/, {}/*arraylength*/, {}/*athrow*/, + {T_SHORT}/*checkcast*/, {T_SHORT}/*instanceof*/, + {}/*monitorenter*/, {}/*monitorexit*/, {T_BYTE}/*wide*/, + {T_SHORT, T_BYTE}/*multianewarray*/, {T_SHORT}/*ifnull*/, + {T_SHORT}/*ifnonnull*/, {T_INT}/*goto_w*/, {T_INT}/*jsr_w*/, + {}/*breakpoint*/, {}, {}, {}, {}, {}, {}, {}, + {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, + {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, + {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, + {}/*impdep1*/, {}/*impdep2*/ + }; + + /** + * Names of opcodes. + */ + public static final String[] OPCODE_NAMES = { + "nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", + "iconst_2", "iconst_3", "iconst_4", "iconst_5", "lconst_0", + "lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0", + "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w", "iload", + "lload", "fload", "dload", "aload", "iload_0", "iload_1", "iload_2", + "iload_3", "lload_0", "lload_1", "lload_2", "lload_3", "fload_0", + "fload_1", "fload_2", "fload_3", "dload_0", "dload_1", "dload_2", + "dload_3", "aload_0", "aload_1", "aload_2", "aload_3", "iaload", + "laload", "faload", "daload", "aaload", "baload", "caload", "saload", + "istore", "lstore", "fstore", "dstore", "astore", "istore_0", + "istore_1", "istore_2", "istore_3", "lstore_0", "lstore_1", + "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", + "fstore_3", "dstore_0", "dstore_1", "dstore_2", "dstore_3", + "astore_0", "astore_1", "astore_2", "astore_3", "iastore", "lastore", + "fastore", "dastore", "aastore", "bastore", "castore", "sastore", + "pop", "pop2", "dup", "dup_x1", "dup_x2", "dup2", "dup2_x1", + "dup2_x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub", "lsub", + "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv", "ldiv", + "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", + "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr", + "iand", "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", + "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", + "i2b", "i2c", "i2s", "lcmp", "fcmpl", "fcmpg", + "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", + "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", "if_icmpgt", + "if_icmple", "if_acmpeq", "if_acmpne", "goto", "jsr", "ret", + "tableswitch", "lookupswitch", "ireturn", "lreturn", "freturn", + "dreturn", "areturn", "return", "getstatic", "putstatic", "getfield", + "putfield", "invokevirtual", "invokespecial", "invokestatic", + "invokeinterface", ILLEGAL_OPCODE, "new", "newarray", "anewarray", + "arraylength", "athrow", "checkcast", "instanceof", "monitorenter", + "monitorexit", "wide", "multianewarray", "ifnull", "ifnonnull", + "goto_w", "jsr_w", "breakpoint", ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, "impdep1", "impdep2" + }; + + /** + * Number of words consumed on operand stack by instructions. + */ + public static final int[] CONSUME_STACK = { + 0/*nop*/, 0/*aconst_null*/, 0/*iconst_m1*/, 0/*iconst_0*/, 0/*iconst_1*/, + 0/*iconst_2*/, 0/*iconst_3*/, 0/*iconst_4*/, 0/*iconst_5*/, 0/*lconst_0*/, + 0/*lconst_1*/, 0/*fconst_0*/, 0/*fconst_1*/, 0/*fconst_2*/, 0/*dconst_0*/, + 0/*dconst_1*/, 0/*bipush*/, 0/*sipush*/, 0/*ldc*/, 0/*ldc_w*/, 0/*ldc2_w*/, 0/*iload*/, + 0/*lload*/, 0/*fload*/, 0/*dload*/, 0/*aload*/, 0/*iload_0*/, 0/*iload_1*/, 0/*iload_2*/, + 0/*iload_3*/, 0/*lload_0*/, 0/*lload_1*/, 0/*lload_2*/, 0/*lload_3*/, 0/*fload_0*/, + 0/*fload_1*/, 0/*fload_2*/, 0/*fload_3*/, 0/*dload_0*/, 0/*dload_1*/, 0/*dload_2*/, + 0/*dload_3*/, 0/*aload_0*/, 0/*aload_1*/, 0/*aload_2*/, 0/*aload_3*/, 2/*iaload*/, + 2/*laload*/, 2/*faload*/, 2/*daload*/, 2/*aaload*/, 2/*baload*/, 2/*caload*/, 2/*saload*/, + 1/*istore*/, 2/*lstore*/, 1/*fstore*/, 2/*dstore*/, 1/*astore*/, 1/*istore_0*/, + 1/*istore_1*/, 1/*istore_2*/, 1/*istore_3*/, 2/*lstore_0*/, 2/*lstore_1*/, + 2/*lstore_2*/, 2/*lstore_3*/, 1/*fstore_0*/, 1/*fstore_1*/, 1/*fstore_2*/, + 1/*fstore_3*/, 2/*dstore_0*/, 2/*dstore_1*/, 2/*dstore_2*/, 2/*dstore_3*/, + 1/*astore_0*/, 1/*astore_1*/, 1/*astore_2*/, 1/*astore_3*/, 3/*iastore*/, 4/*lastore*/, + 3/*fastore*/, 4/*dastore*/, 3/*aastore*/, 3/*bastore*/, 3/*castore*/, 3/*sastore*/, + 1/*pop*/, 2/*pop2*/, 1/*dup*/, 2/*dup_x1*/, 3/*dup_x2*/, 2/*dup2*/, 3/*dup2_x1*/, + 4/*dup2_x2*/, 2/*swap*/, 2/*iadd*/, 4/*ladd*/, 2/*fadd*/, 4/*dadd*/, 2/*isub*/, 4/*lsub*/, + 2/*fsub*/, 4/*dsub*/, 2/*imul*/, 4/*lmul*/, 2/*fmul*/, 4/*dmul*/, 2/*idiv*/, 4/*ldiv*/, + 2/*fdiv*/, 4/*ddiv*/, 2/*irem*/, 4/*lrem*/, 2/*frem*/, 4/*drem*/, 1/*ineg*/, 2/*lneg*/, + 1/*fneg*/, 2/*dneg*/, 2/*ishl*/, 3/*lshl*/, 2/*ishr*/, 3/*lshr*/, 2/*iushr*/, 3/*lushr*/, + 2/*iand*/, 4/*land*/, 2/*ior*/, 4/*lor*/, 2/*ixor*/, 4/*lxor*/, 0/*iinc*/, + 1/*i2l*/, 1/*i2f*/, 1/*i2d*/, 2/*l2i*/, 2/*l2f*/, 2/*l2d*/, 1/*f2i*/, 1/*f2l*/, + 1/*f2d*/, 2/*d2i*/, 2/*d2l*/, 2/*d2f*/, 1/*i2b*/, 1/*i2c*/, 1/*i2s*/, + 4/*lcmp*/, 2/*fcmpl*/, 2/*fcmpg*/, 4/*dcmpl*/, 4/*dcmpg*/, 1/*ifeq*/, 1/*ifne*/, + 1/*iflt*/, 1/*ifge*/, 1/*ifgt*/, 1/*ifle*/, 2/*if_icmpeq*/, 2/*if_icmpne*/, 2/*if_icmplt*/, + 2 /*if_icmpge*/, 2/*if_icmpgt*/, 2/*if_icmple*/, 2/*if_acmpeq*/, 2/*if_acmpne*/, + 0/*goto*/, 0/*jsr*/, 0/*ret*/, 1/*tableswitch*/, 1/*lookupswitch*/, 1/*ireturn*/, + 2/*lreturn*/, 1/*freturn*/, 2/*dreturn*/, 1/*areturn*/, 0/*return*/, 0/*getstatic*/, + UNPREDICTABLE/*putstatic*/, 1/*getfield*/, UNPREDICTABLE/*putfield*/, + UNPREDICTABLE/*invokevirtual*/, UNPREDICTABLE/*invokespecial*/, + UNPREDICTABLE/*invokestatic*/, + UNPREDICTABLE/*invokeinterface*/, UNDEFINED, 0/*new*/, 1/*newarray*/, 1/*anewarray*/, + 1/*arraylength*/, 1/*athrow*/, 1/*checkcast*/, 1/*instanceof*/, 1/*monitorenter*/, + 1/*monitorexit*/, 0/*wide*/, UNPREDICTABLE/*multianewarray*/, 1/*ifnull*/, 1/*ifnonnull*/, + 0/*goto_w*/, 0/*jsr_w*/, 0/*breakpoint*/, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNPREDICTABLE/*impdep1*/, UNPREDICTABLE/*impdep2*/ + }; + + /** + * Number of words produced onto operand stack by instructions. + */ + public static final int[] PRODUCE_STACK = { + 0/*nop*/, 1/*aconst_null*/, 1/*iconst_m1*/, 1/*iconst_0*/, 1/*iconst_1*/, + 1/*iconst_2*/, 1/*iconst_3*/, 1/*iconst_4*/, 1/*iconst_5*/, 2/*lconst_0*/, + 2/*lconst_1*/, 1/*fconst_0*/, 1/*fconst_1*/, 1/*fconst_2*/, 2/*dconst_0*/, + 2/*dconst_1*/, 1/*bipush*/, 1/*sipush*/, 1/*ldc*/, 1/*ldc_w*/, 2/*ldc2_w*/, 1/*iload*/, + 2/*lload*/, 1/*fload*/, 2/*dload*/, 1/*aload*/, 1/*iload_0*/, 1/*iload_1*/, 1/*iload_2*/, + 1/*iload_3*/, 2/*lload_0*/, 2/*lload_1*/, 2/*lload_2*/, 2/*lload_3*/, 1/*fload_0*/, + 1/*fload_1*/, 1/*fload_2*/, 1/*fload_3*/, 2/*dload_0*/, 2/*dload_1*/, 2/*dload_2*/, + 2/*dload_3*/, 1/*aload_0*/, 1/*aload_1*/, 1/*aload_2*/, 1/*aload_3*/, 1/*iaload*/, + 2/*laload*/, 1/*faload*/, 2/*daload*/, 1/*aaload*/, 1/*baload*/, 1/*caload*/, 1/*saload*/, + 0/*istore*/, 0/*lstore*/, 0/*fstore*/, 0/*dstore*/, 0/*astore*/, 0/*istore_0*/, + 0/*istore_1*/, 0/*istore_2*/, 0/*istore_3*/, 0/*lstore_0*/, 0/*lstore_1*/, + 0/*lstore_2*/, 0/*lstore_3*/, 0/*fstore_0*/, 0/*fstore_1*/, 0/*fstore_2*/, + 0/*fstore_3*/, 0/*dstore_0*/, 0/*dstore_1*/, 0/*dstore_2*/, 0/*dstore_3*/, + 0/*astore_0*/, 0/*astore_1*/, 0/*astore_2*/, 0/*astore_3*/, 0/*iastore*/, 0/*lastore*/, + 0/*fastore*/, 0/*dastore*/, 0/*aastore*/, 0/*bastore*/, 0/*castore*/, 0/*sastore*/, + 0/*pop*/, 0/*pop2*/, 2/*dup*/, 3/*dup_x1*/, 4/*dup_x2*/, 4/*dup2*/, 5/*dup2_x1*/, + 6/*dup2_x2*/, 2/*swap*/, 1/*iadd*/, 2/*ladd*/, 1/*fadd*/, 2/*dadd*/, 1/*isub*/, 2/*lsub*/, + 1/*fsub*/, 2/*dsub*/, 1/*imul*/, 2/*lmul*/, 1/*fmul*/, 2/*dmul*/, 1/*idiv*/, 2/*ldiv*/, + 1/*fdiv*/, 2/*ddiv*/, 1/*irem*/, 2/*lrem*/, 1/*frem*/, 2/*drem*/, 1/*ineg*/, 2/*lneg*/, + 1/*fneg*/, 2/*dneg*/, 1/*ishl*/, 2/*lshl*/, 1/*ishr*/, 2/*lshr*/, 1/*iushr*/, 2/*lushr*/, + 1/*iand*/, 2/*land*/, 1/*ior*/, 2/*lor*/, 1/*ixor*/, 2/*lxor*/, + 0/*iinc*/, 2/*i2l*/, 1/*i2f*/, 2/*i2d*/, 1/*l2i*/, 1/*l2f*/, 2/*l2d*/, 1/*f2i*/, + 2/*f2l*/, 2/*f2d*/, 1/*d2i*/, 2/*d2l*/, 1/*d2f*/, + 1/*i2b*/, 1/*i2c*/, 1/*i2s*/, 1/*lcmp*/, 1/*fcmpl*/, 1/*fcmpg*/, + 1/*dcmpl*/, 1/*dcmpg*/, 0/*ifeq*/, 0/*ifne*/, 0/*iflt*/, 0/*ifge*/, 0/*ifgt*/, 0/*ifle*/, + 0/*if_icmpeq*/, 0/*if_icmpne*/, 0/*if_icmplt*/, 0/*if_icmpge*/, 0/*if_icmpgt*/, + 0/*if_icmple*/, 0/*if_acmpeq*/, 0/*if_acmpne*/, 0/*goto*/, 1/*jsr*/, 0/*ret*/, + 0/*tableswitch*/, 0/*lookupswitch*/, 0/*ireturn*/, 0/*lreturn*/, 0/*freturn*/, + 0/*dreturn*/, 0/*areturn*/, 0/*return*/, UNPREDICTABLE/*getstatic*/, 0/*putstatic*/, + UNPREDICTABLE/*getfield*/, 0/*putfield*/, UNPREDICTABLE/*invokevirtual*/, + UNPREDICTABLE/*invokespecial*/, UNPREDICTABLE/*invokestatic*/, + UNPREDICTABLE/*invokeinterface*/, UNDEFINED, 1/*new*/, 1/*newarray*/, 1/*anewarray*/, + 1/*arraylength*/, 1/*athrow*/, 1/*checkcast*/, 1/*instanceof*/, 0/*monitorenter*/, + 0/*monitorexit*/, 0/*wide*/, 1/*multianewarray*/, 0/*ifnull*/, 0/*ifnonnull*/, + 0/*goto_w*/, 1/*jsr_w*/, 0/*breakpoint*/, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNPREDICTABLE/*impdep1*/, UNPREDICTABLE/*impdep2*/ + }; + + /** Attributes and their corresponding names. + */ + public static final byte ATTR_UNKNOWN = -1; + public static final byte ATTR_SOURCE_FILE = 0; + public static final byte ATTR_CONSTANT_VALUE = 1; + public static final byte ATTR_CODE = 2; + public static final byte ATTR_EXCEPTIONS = 3; + public static final byte ATTR_LINE_NUMBER_TABLE = 4; + public static final byte ATTR_LOCAL_VARIABLE_TABLE = 5; + public static final byte ATTR_INNER_CLASSES = 6; + public static final byte ATTR_SYNTHETIC = 7; + public static final byte ATTR_DEPRECATED = 8; + public static final byte ATTR_PMG = 9; + public static final byte ATTR_SIGNATURE = 10; + public static final byte ATTR_STACK_MAP = 11; + public static final byte ATTR_RUNTIMEVISIBLE_ANNOTATIONS = 12; + public static final byte ATTR_RUNTIMEINVISIBLE_ANNOTATIONS = 13; + public static final byte ATTR_RUNTIMEVISIBLE_PARAMETER_ANNOTATIONS = 14; + public static final byte ATTR_RUNTIMEINVISIBLE_PARAMETER_ANNOTATIONS = 15; + public static final byte ATTR_ANNOTATION_DEFAULT = 16; + + public static final short KNOWN_ATTRIBUTES = 12;//should be 17 + + public static final String[] ATTRIBUTE_NAMES = { + "SourceFile", "ConstantValue", "Code", "Exceptions", + "LineNumberTable", "LocalVariableTable", + "InnerClasses", "Synthetic", "Deprecated", + "PMGClass", "Signature", "StackMap", + "RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations", + "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", + "AnnotationDefault" + }; + + /** Constants used in the StackMap attribute. + */ + public static final byte ITEM_Bogus = 0; + public static final byte ITEM_Integer = 1; + public static final byte ITEM_Float = 2; + public static final byte ITEM_Double = 3; + public static final byte ITEM_Long = 4; + public static final byte ITEM_Null = 5; + public static final byte ITEM_InitObject = 6; + public static final byte ITEM_Object = 7; + public static final byte ITEM_NewObject = 8; + + public static final String[] ITEM_NAMES = { + "Bogus", "Integer", "Float", "Double", "Long", + "Null", "InitObject", "Object", "NewObject" + }; +} diff --git a/src/org/apache/bcel/ExceptionConstants.java b/src/org/apache/bcel/ExceptionConstants.java new file mode 100644 index 0000000..e42aa58 --- /dev/null +++ b/src/org/apache/bcel/ExceptionConstants.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel; + +/** + * Exception constants. + * + * @version $Id: ExceptionConstants.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author E. Haase + */ +public interface ExceptionConstants { + + /** The mother of all exceptions + */ + public static final Class THROWABLE = Throwable.class; + /** Super class of any run-time exception + */ + public static final Class RUNTIME_EXCEPTION = RuntimeException.class; + /** Super class of any linking exception (aka Linkage Error) + */ + public static final Class LINKING_EXCEPTION = LinkageError.class; + /** Linking Exceptions + */ + public static final Class CLASS_CIRCULARITY_ERROR = ClassCircularityError.class; + public static final Class CLASS_FORMAT_ERROR = ClassFormatError.class; + public static final Class EXCEPTION_IN_INITIALIZER_ERROR = ExceptionInInitializerError.class; + public static final Class INCOMPATIBLE_CLASS_CHANGE_ERROR = IncompatibleClassChangeError.class; + public static final Class ABSTRACT_METHOD_ERROR = AbstractMethodError.class; + public static final Class ILLEGAL_ACCESS_ERROR = IllegalAccessError.class; + public static final Class INSTANTIATION_ERROR = InstantiationError.class; + public static final Class NO_SUCH_FIELD_ERROR = NoSuchFieldError.class; + public static final Class NO_SUCH_METHOD_ERROR = NoSuchMethodError.class; + public static final Class NO_CLASS_DEF_FOUND_ERROR = NoClassDefFoundError.class; + public static final Class UNSATISFIED_LINK_ERROR = UnsatisfiedLinkError.class; + public static final Class VERIFY_ERROR = VerifyError.class; + /* UnsupportedClassVersionError is new in JDK 1.2 */ + //public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class; + /** Run-Time Exceptions + */ + public static final Class NULL_POINTER_EXCEPTION = NullPointerException.class; + public static final Class ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION = ArrayIndexOutOfBoundsException.class; + public static final Class ARITHMETIC_EXCEPTION = ArithmeticException.class; + public static final Class NEGATIVE_ARRAY_SIZE_EXCEPTION = NegativeArraySizeException.class; + public static final Class CLASS_CAST_EXCEPTION = ClassCastException.class; + public static final Class ILLEGAL_MONITOR_STATE = IllegalMonitorStateException.class; + /** Pre-defined exception arrays according to chapters 5.1-5.4 of the Java Virtual + * Machine Specification + */ + public static final Class[] EXCS_CLASS_AND_INTERFACE_RESOLUTION = { + NO_CLASS_DEF_FOUND_ERROR, CLASS_FORMAT_ERROR, VERIFY_ERROR, ABSTRACT_METHOD_ERROR, + EXCEPTION_IN_INITIALIZER_ERROR, ILLEGAL_ACCESS_ERROR + }; // Chapter 5.1 + public static final Class[] EXCS_FIELD_AND_METHOD_RESOLUTION = { + NO_SUCH_FIELD_ERROR, ILLEGAL_ACCESS_ERROR, NO_SUCH_METHOD_ERROR + }; // Chapter 5.2 + public static final Class[] EXCS_INTERFACE_METHOD_RESOLUTION = new Class[0]; // Chapter 5.3 (as below) + public static final Class[] EXCS_STRING_RESOLUTION = new Class[0]; + // Chapter 5.4 (no errors but the ones that _always_ could happen! How stupid.) + public static final Class[] EXCS_ARRAY_EXCEPTION = { + NULL_POINTER_EXCEPTION, ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION + }; +} diff --git a/src/org/apache/bcel/Repository.java b/src/org/apache/bcel/Repository.java new file mode 100644 index 0000000..3dcb3f3 --- /dev/null +++ b/src/org/apache/bcel/Repository.java @@ -0,0 +1,261 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel; + +import java.io.IOException; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.util.ClassPath; +import org.apache.bcel.util.SyntheticRepository; + +/** + * The repository maintains informations about class interdependencies, e.g., + * whether a class is a sub-class of another. Delegates actual class loading + * to SyntheticRepository with current class path by default. + * + * @see org.apache.bcel.util.Repository + * @see org.apache.bcel.util.SyntheticRepository + * + * @version $Id: Repository.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class Repository { + + private static org.apache.bcel.util.Repository _repository = SyntheticRepository.getInstance(); + + + /** @return currently used repository instance + */ + public static org.apache.bcel.util.Repository getRepository() { + return _repository; + } + + + /** Set repository instance to be used for class loading + */ + public static void setRepository( org.apache.bcel.util.Repository rep ) { + _repository = rep; + } + + + /** Lookup class somewhere found on your CLASSPATH, or whereever the + * repository instance looks for it. + * + * @return class object for given fully qualified class name + * @throws ClassNotFoundException if the class could not be found or + * parsed correctly + */ + public static JavaClass lookupClass( String class_name ) throws ClassNotFoundException { + return _repository.loadClass(class_name); + } + + + /** + * Try to find class source using the internal repository instance. + * @see Class + * @return JavaClass object for given runtime class + * @throws ClassNotFoundException if the class could not be found or + * parsed correctly + */ + public static JavaClass lookupClass( Class clazz ) throws ClassNotFoundException { + return _repository.loadClass(clazz); + } + + + /** + * @return class file object for given Java class by looking on the + * system class path; returns null if the class file can't be + * found + */ + public static ClassPath.ClassFile lookupClassFile( String class_name ) { + try { + ClassPath path = _repository.getClassPath(); + if (path == null) { + return null; + } + return path.getClassFile(class_name); + } catch (IOException e) { + return null; + } + } + + + /** Clear the repository. + */ + public static void clearCache() { + _repository.clear(); + } + + + /** + * Add clazz to repository if there isn't an equally named class already in there. + * + * @return old entry in repository + */ + public static JavaClass addClass( JavaClass clazz ) { + JavaClass old = _repository.findClass(clazz.getClassName()); + _repository.storeClass(clazz); + return old; + } + + + /** + * Remove class with given (fully qualified) name from repository. + */ + public static void removeClass( String clazz ) { + _repository.removeClass(_repository.findClass(clazz)); + } + + + /** + * Remove given class from repository. + */ + public static void removeClass( JavaClass clazz ) { + _repository.removeClass(clazz); + } + + + /** + * @return list of super classes of clazz in ascending order, i.e., + * Object is always the last element + * @throws ClassNotFoundException if any of the superclasses can't be found + */ + public static JavaClass[] getSuperClasses( JavaClass clazz ) throws ClassNotFoundException { + return clazz.getSuperClasses(); + } + + + /** + * @return list of super classes of clazz in ascending order, i.e., + * Object is always the last element. + * @throws ClassNotFoundException if the named class or any of its + * superclasses can't be found + */ + public static JavaClass[] getSuperClasses( String class_name ) throws ClassNotFoundException { + JavaClass jc = lookupClass(class_name); + return getSuperClasses(jc); + } + + + /** + * @return all interfaces implemented by class and its super + * classes and the interfaces that those interfaces extend, and so on. + * (Some people call this a transitive hull). + * @throws ClassNotFoundException if any of the class's + * superclasses or superinterfaces can't be found + */ + public static JavaClass[] getInterfaces( JavaClass clazz ) throws ClassNotFoundException { + return clazz.getAllInterfaces(); + } + + + /** + * @return all interfaces implemented by class and its super + * classes and the interfaces that extend those interfaces, and so on + * @throws ClassNotFoundException if the named class can't be found, + * or if any of its superclasses or superinterfaces can't be found + */ + public static JavaClass[] getInterfaces( String class_name ) throws ClassNotFoundException { + return getInterfaces(lookupClass(class_name)); + } + + + /** + * Equivalent to runtime "instanceof" operator. + * @return true, if clazz is an instance of super_class + * @throws ClassNotFoundException if any superclasses or superinterfaces + * of clazz can't be found + */ + public static boolean instanceOf( JavaClass clazz, JavaClass super_class ) + throws ClassNotFoundException { + return clazz.instanceOf(super_class); + } + + + /** + * @return true, if clazz is an instance of super_class + * @throws ClassNotFoundException if either clazz or super_class + * can't be found + */ + public static boolean instanceOf( String clazz, String super_class ) + throws ClassNotFoundException { + return instanceOf(lookupClass(clazz), lookupClass(super_class)); + } + + + /** + * @return true, if clazz is an instance of super_class + * @throws ClassNotFoundException if super_class can't be found + */ + public static boolean instanceOf( JavaClass clazz, String super_class ) + throws ClassNotFoundException { + return instanceOf(clazz, lookupClass(super_class)); + } + + + /** + * @return true, if clazz is an instance of super_class + * @throws ClassNotFoundException if clazz can't be found + */ + public static boolean instanceOf( String clazz, JavaClass super_class ) + throws ClassNotFoundException { + return instanceOf(lookupClass(clazz), super_class); + } + + + /** + * @return true, if clazz is an implementation of interface inter + * @throws ClassNotFoundException if any superclasses or superinterfaces + * of clazz can't be found + */ + public static boolean implementationOf( JavaClass clazz, JavaClass inter ) + throws ClassNotFoundException { + return clazz.implementationOf(inter); + } + + + /** + * @return true, if clazz is an implementation of interface inter + * @throws ClassNotFoundException if clazz, inter, or any superclasses + * or superinterfaces of clazz can't be found + */ + public static boolean implementationOf( String clazz, String inter ) + throws ClassNotFoundException { + return implementationOf(lookupClass(clazz), lookupClass(inter)); + } + + + /** + * @return true, if clazz is an implementation of interface inter + * @throws ClassNotFoundException if inter or any superclasses + * or superinterfaces of clazz can't be found + */ + public static boolean implementationOf( JavaClass clazz, String inter ) + throws ClassNotFoundException { + return implementationOf(clazz, lookupClass(inter)); + } + + + /** + * @return true, if clazz is an implementation of interface inter + * @throws ClassNotFoundException if clazz or any superclasses or + * superinterfaces of clazz can't be found + */ + public static boolean implementationOf( String clazz, JavaClass inter ) + throws ClassNotFoundException { + return implementationOf(lookupClass(clazz), inter); + } +} diff --git a/src/org/apache/bcel/classfile/AccessFlags.java b/src/org/apache/bcel/classfile/AccessFlags.java new file mode 100644 index 0000000..981babc --- /dev/null +++ b/src/org/apache/bcel/classfile/AccessFlags.java @@ -0,0 +1,238 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import org.apache.bcel.Constants; + +/** + * Super class for all objects that have modifiers like private, final, ... + * I.e. classes, fields, and methods. + * + * @version $Id: AccessFlags.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class AccessFlags implements java.io.Serializable { + + protected int access_flags; + + + public AccessFlags() { + } + + + /** + * @param a inital access flags + */ + public AccessFlags(int a) { + access_flags = a; + } + + + /** + * @return Access flags of the object aka. "modifiers". + */ + public final int getAccessFlags() { + return access_flags; + } + + + /** + * @return Access flags of the object aka. "modifiers". + */ + public final int getModifiers() { + return access_flags; + } + + + /** Set access flags aka "modifiers". + * @param access_flags Access flags of the object. + */ + public final void setAccessFlags( int access_flags ) { + this.access_flags = access_flags; + } + + + /** Set access flags aka "modifiers". + * @param access_flags Access flags of the object. + */ + public final void setModifiers( int access_flags ) { + setAccessFlags(access_flags); + } + + + private final void setFlag( int flag, boolean set ) { + if ((access_flags & flag) != 0) { // Flag is set already + if (!set) { + access_flags ^= flag; + } + } else { // Flag not set + if (set) { + access_flags |= flag; + } + } + } + + + public final void isPublic( boolean flag ) { + setFlag(Constants.ACC_PUBLIC, flag); + } + + + public final boolean isPublic() { + return (access_flags & Constants.ACC_PUBLIC) != 0; + } + + + public final void isPrivate( boolean flag ) { + setFlag(Constants.ACC_PRIVATE, flag); + } + + + public final boolean isPrivate() { + return (access_flags & Constants.ACC_PRIVATE) != 0; + } + + + public final void isProtected( boolean flag ) { + setFlag(Constants.ACC_PROTECTED, flag); + } + + + public final boolean isProtected() { + return (access_flags & Constants.ACC_PROTECTED) != 0; + } + + + public final void isStatic( boolean flag ) { + setFlag(Constants.ACC_STATIC, flag); + } + + + public final boolean isStatic() { + return (access_flags & Constants.ACC_STATIC) != 0; + } + + + public final void isFinal( boolean flag ) { + setFlag(Constants.ACC_FINAL, flag); + } + + + public final boolean isFinal() { + return (access_flags & Constants.ACC_FINAL) != 0; + } + + + public final void isSynchronized( boolean flag ) { + setFlag(Constants.ACC_SYNCHRONIZED, flag); + } + + + public final boolean isSynchronized() { + return (access_flags & Constants.ACC_SYNCHRONIZED) != 0; + } + + + public final void isVolatile( boolean flag ) { + setFlag(Constants.ACC_VOLATILE, flag); + } + + + public final boolean isVolatile() { + return (access_flags & Constants.ACC_VOLATILE) != 0; + } + + + public final void isTransient( boolean flag ) { + setFlag(Constants.ACC_TRANSIENT, flag); + } + + + public final boolean isTransient() { + return (access_flags & Constants.ACC_TRANSIENT) != 0; + } + + + public final void isNative( boolean flag ) { + setFlag(Constants.ACC_NATIVE, flag); + } + + + public final boolean isNative() { + return (access_flags & Constants.ACC_NATIVE) != 0; + } + + + public final void isInterface( boolean flag ) { + setFlag(Constants.ACC_INTERFACE, flag); + } + + + public final boolean isInterface() { + return (access_flags & Constants.ACC_INTERFACE) != 0; + } + + + public final void isAbstract( boolean flag ) { + setFlag(Constants.ACC_ABSTRACT, flag); + } + + + public final boolean isAbstract() { + return (access_flags & Constants.ACC_ABSTRACT) != 0; + } + + + public final void isStrictfp( boolean flag ) { + setFlag(Constants.ACC_STRICT, flag); + } + + + public final boolean isStrictfp() { + return (access_flags & Constants.ACC_STRICT) != 0; + } + + + public final void isSynthetic( boolean flag ) { + setFlag(Constants.ACC_SYNTHETIC, flag); + } + + + public final boolean isSynthetic() { + return (access_flags & Constants.ACC_SYNTHETIC) != 0; + } + + + public final void isAnnotation( boolean flag ) { + setFlag(Constants.ACC_ANNOTATION, flag); + } + + + public final boolean isAnnotation() { + return (access_flags & Constants.ACC_ANNOTATION) != 0; + } + + + public final void isEnum( boolean flag ) { + setFlag(Constants.ACC_ENUM, flag); + } + + + public final boolean isEnum() { + return (access_flags & Constants.ACC_ENUM) != 0; + } +} diff --git a/src/org/apache/bcel/classfile/Attribute.java b/src/org/apache/bcel/classfile/Attribute.java new file mode 100644 index 0000000..c34b097 --- /dev/null +++ b/src/org/apache/bcel/classfile/Attribute.java @@ -0,0 +1,278 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import org.apache.bcel.Constants; + +/** + * Abstract super class for Attribute objects. Currently the + * ConstantValue, SourceFile, Code, + * Exceptiontable, LineNumberTable, + * LocalVariableTable, InnerClasses and + * Synthetic attributes are supported. The + * Unknown attribute stands for non-standard-attributes. + * + * @version $Id: Attribute.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see ConstantValue + * @see SourceFile + * @see Code + * @see Unknown + * @see ExceptionTable + * @see LineNumberTable + * @see LocalVariableTable + * @see InnerClasses + * @see Synthetic + * @see Deprecated + * @see Signature + */ +public abstract class Attribute implements Cloneable, Node, Serializable { + + protected int name_index; // Points to attribute name in constant pool + protected int length; // Content length of attribute field + protected byte tag; // Tag to distiguish subclasses + protected ConstantPool constant_pool; + + + protected Attribute(byte tag, int name_index, int length, ConstantPool constant_pool) { + this.tag = tag; + this.name_index = name_index; + this.length = length; + this.constant_pool = constant_pool; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public abstract void accept( Visitor v ); + + + /** + * Dump attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public void dump( DataOutputStream file ) throws IOException { + file.writeShort(name_index); + file.writeInt(length); + } + + private static Map readers = new HashMap(); + + + /** Add an Attribute reader capable of parsing (user-defined) attributes + * named "name". You should not add readers for the standard attributes + * such as "LineNumberTable", because those are handled internally. + * + * @param name the name of the attribute as stored in the class file + * @param r the reader object + */ + public static void addAttributeReader( String name, AttributeReader r ) { + readers.put(name, r); + } + + + /** Remove attribute reader + * + * @param name the name of the attribute as stored in the class file + */ + public static void removeAttributeReader( String name ) { + readers.remove(name); + } + + + /* Class method reads one attribute from the input data stream. + * This method must not be accessible from the outside. It is + * called by the Field and Method constructor methods. + * + * @see Field + * @see Method + * @param file Input stream + * @param constant_pool Array of constants + * @return Attribute + * @throws IOException + * @throws ClassFormatException + */ + public static final Attribute readAttribute( DataInputStream file, ConstantPool constant_pool ) + throws IOException, ClassFormatException { + ConstantUtf8 c; + String name; + int name_index; + int length; + byte tag = Constants.ATTR_UNKNOWN; // Unknown attribute + // Get class name from constant pool via `name_index' indirection + name_index = file.readUnsignedShort(); + c = (ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8); + name = c.getBytes(); + // Length of data in bytes + length = file.readInt(); + // Compare strings to find known attribute + for (byte i = 0; i < Constants.KNOWN_ATTRIBUTES; i++) { + if (name.equals(Constants.ATTRIBUTE_NAMES[i])) { + tag = i; // found! + break; + } + } + // Call proper constructor, depending on `tag' + switch (tag) { + case Constants.ATTR_UNKNOWN: + AttributeReader r = (AttributeReader) readers.get(name); + if (r != null) { + return r.createAttribute(name_index, length, file, constant_pool); + } + return new Unknown(name_index, length, file, constant_pool); + case Constants.ATTR_CONSTANT_VALUE: + return new ConstantValue(name_index, length, file, constant_pool); + case Constants.ATTR_SOURCE_FILE: + return new SourceFile(name_index, length, file, constant_pool); + case Constants.ATTR_CODE: + return new Code(name_index, length, file, constant_pool); + case Constants.ATTR_EXCEPTIONS: + return new ExceptionTable(name_index, length, file, constant_pool); + case Constants.ATTR_LINE_NUMBER_TABLE: + return new LineNumberTable(name_index, length, file, constant_pool); + case Constants.ATTR_LOCAL_VARIABLE_TABLE: + return new LocalVariableTable(name_index, length, file, constant_pool); + case Constants.ATTR_INNER_CLASSES: + return new InnerClasses(name_index, length, file, constant_pool); + case Constants.ATTR_SYNTHETIC: + return new Synthetic(name_index, length, file, constant_pool); + case Constants.ATTR_DEPRECATED: + return new Deprecated(name_index, length, file, constant_pool); + case Constants.ATTR_PMG: + return new PMGClass(name_index, length, file, constant_pool); + case Constants.ATTR_SIGNATURE: + return new Signature(name_index, length, file, constant_pool); + case Constants.ATTR_STACK_MAP: + return new StackMap(name_index, length, file, constant_pool); + // case Constants.ATTR_RUNTIMEVISIBLE_ANNOTATIONS: + // return new RuntimeVisibleAnnotations(name_index, length, file, constant_pool); + // case Constants.ATTR_RUNTIMEINVISIBLE_ANNOTATIONS: + // return new RuntimeInvisibleAnnotations(name_index, length, file, constant_pool); + // case Constants.ATTR_RUNTIMEVISIBLE_PARAMETER_ANNOTATIONS: + // return new RuntimeVisibleParameterAnnotations(name_index, length, file, constant_pool); + // case Constants.ATTR_RUNTIMEINVISIBLE_PARAMETER_ANNOTATIONS: + // return new RuntimeInvisibleParameterAnnotations(name_index, length, file, constant_pool); + // case Constants.ATTR_ANNOTATION_DEFAULT: + // return new AnnotationDefault(name_index, length, file, constant_pool); + default: // Never reached + throw new IllegalStateException("Ooops! default case reached."); + } + } + + + /** + * @return Length of attribute field in bytes. + */ + public final int getLength() { + return length; + } + + + /** + * @param length length in bytes. + */ + public final void setLength( int length ) { + this.length = length; + } + + + /** + * @param name_index of attribute. + */ + public final void setNameIndex( int name_index ) { + this.name_index = name_index; + } + + + /** + * @return Name index in constant pool of attribute name. + */ + public final int getNameIndex() { + return name_index; + } + + + /** + * @return Tag of attribute, i.e., its type. Value may not be altered, thus + * there is no setTag() method. + */ + public final byte getTag() { + return tag; + } + + + /** + * @return Constant pool used by this object. + * @see ConstantPool + */ + public final ConstantPool getConstantPool() { + return constant_pool; + } + + + /** + * @param constant_pool Constant pool to be used for this object. + * @see ConstantPool + */ + public final void setConstantPool( ConstantPool constant_pool ) { + this.constant_pool = constant_pool; + } + + + /** + * Use copy() if you want to have a deep copy(), i.e., with all references + * copied correctly. + * + * @return shallow copy of this attribute + */ + public Object clone() { + Object o = null; + try { + o = super.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); // Never occurs + } + return o; + } + + + /** + * @return deep copy of this attribute + */ + public abstract Attribute copy( ConstantPool _constant_pool ); + + + /** + * @return attribute name. + */ + public String toString() { + return Constants.ATTRIBUTE_NAMES[tag]; + } +} diff --git a/src/org/apache/bcel/classfile/AttributeReader.java b/src/org/apache/bcel/classfile/AttributeReader.java new file mode 100644 index 0000000..bd6c330 --- /dev/null +++ b/src/org/apache/bcel/classfile/AttributeReader.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +/** + * Unknown (non-standard) attributes may be read via user-defined factory + * objects that can be registered with the Attribute.addAttributeReader + * method. These factory objects should implement this interface. + + * @see Attribute + * @version $Id: AttributeReader.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface AttributeReader { + + /** + When this attribute reader is added via the static method + Attribute.addAttributeReader, an attribute name is associated with it. + As the class file parser parses attributes, it will call various + AttributeReaders based on the name of the attributes it is + constructing. + + @param name_index An index into the constant pool, indexing a + ConstantUtf8 that represents the name of the attribute. + + @param length The length of the data contained in the attribute. This + is written into the constant pool and should agree with what the + factory expects the length to be. + + @param file This is the data input stream that the factory needs to read + its data from. + + @param constant_pool This is the constant pool associated with the + Attribute that we are constructing. + + @return The user-defined AttributeReader should take this data and use + it to construct an attribute. In the case of errors, a null can be + returned which will cause the parsing of the class file to fail. + + @see Attribute#addAttributeReader( String, AttributeReader ) + */ + public Attribute createAttribute( int name_index, int length, java.io.DataInputStream file, + ConstantPool constant_pool ); +} diff --git a/src/org/apache/bcel/classfile/ClassFormatException.java b/src/org/apache/bcel/classfile/ClassFormatException.java new file mode 100644 index 0000000..1346419 --- /dev/null +++ b/src/org/apache/bcel/classfile/ClassFormatException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +/** + * Thrown when the BCEL attempts to read a class file and determines + * that the file is malformed or otherwise cannot be interpreted as a + * class file. + * + * @version $Id: ClassFormatException.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ClassFormatException extends RuntimeException { + + public ClassFormatException() { + super(); + } + + + public ClassFormatException(String s) { + super(s); + } +} diff --git a/src/org/apache/bcel/classfile/ClassParser.java b/src/org/apache/bcel/classfile/ClassParser.java new file mode 100644 index 0000000..df11e22 --- /dev/null +++ b/src/org/apache/bcel/classfile/ClassParser.java @@ -0,0 +1,295 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.apache.bcel.Constants; + +/** + * Wrapper class that parses a given Java .class file. The method parse returns a + * JavaClass object on success. When an I/O error or an + * inconsistency occurs an appropiate exception is propagated back to + * the caller. + * + * The structure and the names comply, except for a few conveniences, + * exactly with the + * JVM specification 1.0. See this paper for + * further details about the structure of a bytecode file. + * + * @version $Id: ClassParser.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class ClassParser { + + private DataInputStream file; + private boolean fileOwned; + private String file_name; + private String zip_file; + private int class_name_index, superclass_name_index; + private int major, minor; // Compiler version + private int access_flags; // Access rights of parsed class + private int[] interfaces; // Names of implemented interfaces + private ConstantPool constant_pool; // collection of constants + private Field[] fields; // class fields, i.e., its variables + private Method[] methods; // methods defined in the class + private Attribute[] attributes; // attributes defined in the class + private boolean is_zip; // Loaded from zip file + private static final int BUFSIZE = 8192; + + + /** + * Parse class from the given stream. + * + * @param file Input stream + * @param file_name File name + */ + public ClassParser(InputStream file, String file_name) { + this.file_name = file_name; + fileOwned = false; + String clazz = file.getClass().getName(); // Not a very clean solution ... + is_zip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar."); + if (file instanceof DataInputStream) { + this.file = (DataInputStream) file; + } else { + this.file = new DataInputStream(new BufferedInputStream(file, BUFSIZE)); + } + } + + + /** Parse class from given .class file. + * + * @param file_name file name + */ + public ClassParser(String file_name) throws IOException { + is_zip = false; + this.file_name = file_name; + fileOwned = true; + } + + + /** Parse class from given .class file in a ZIP-archive + * + * @param zip_file zip file name + * @param file_name file name + */ + public ClassParser(String zip_file, String file_name) { + is_zip = true; + fileOwned = true; + this.zip_file = zip_file; + this.file_name = file_name; + } + + + /** + * Parse the given Java class file and return an object that represents + * the contained data, i.e., constants, methods, fields and commands. + * A ClassFormatException is raised, if the file is not a valid + * .class file. (This does not include verification of the byte code as it + * is performed by the java interpreter). + * + * @return Class object representing the parsed class file + * @throws IOException + * @throws ClassFormatException + */ + public JavaClass parse() throws IOException, ClassFormatException { + ZipFile zip = null; + try { + if (fileOwned) { + if (is_zip) { + zip = new ZipFile(zip_file); + ZipEntry entry = zip.getEntry(file_name); + file = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry), + BUFSIZE)); + } else { + file = new DataInputStream(new BufferedInputStream(new FileInputStream( + file_name), BUFSIZE)); + } + } + /****************** Read headers ********************************/ + // Check magic tag of class file + readID(); + // Get compiler version + readVersion(); + /****************** Read constant pool and related **************/ + // Read constant pool entries + readConstantPool(); + // Get class information + readClassInfo(); + // Get interface information, i.e., implemented interfaces + readInterfaces(); + /****************** Read class fields and methods ***************/ + // Read class fields, i.e., the variables of the class + readFields(); + // Read class methods, i.e., the functions in the class + readMethods(); + // Read class attributes + readAttributes(); + // Check for unknown variables + //Unknown[] u = Unknown.getUnknownAttributes(); + //for(int i=0; i < u.length; i++) + // System.err.println("WARNING: " + u[i]); + // Everything should have been read now + // if(file.available() > 0) { + // int bytes = file.available(); + // byte[] buf = new byte[bytes]; + // file.read(buf); + // if(!(is_zip && (buf.length == 1))) { + // System.err.println("WARNING: Trailing garbage at end of " + file_name); + // System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf)); + // } + // } + } finally { + // Read everything of interest, so close the file + if (fileOwned) { + file.close(); + if (zip != null) { + zip.close(); + } + } + } + // Return the information we have gathered in a new object + return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor, + access_flags, constant_pool, interfaces, fields, methods, attributes, is_zip + ? JavaClass.ZIP + : JavaClass.FILE); + } + + + /** + * Read information about the attributes of the class. + * @throws IOException + * @throws ClassFormatException + */ + private final void readAttributes() throws IOException, ClassFormatException { + int attributes_count; + attributes_count = file.readUnsignedShort(); + attributes = new Attribute[attributes_count]; + for (int i = 0; i < attributes_count; i++) { + attributes[i] = Attribute.readAttribute(file, constant_pool); + } + } + + + /** + * Read information about the class and its super class. + * @throws IOException + * @throws ClassFormatException + */ + private final void readClassInfo() throws IOException, ClassFormatException { + access_flags = file.readUnsignedShort(); + /* Interfaces are implicitely abstract, the flag should be set + * according to the JVM specification. + */ + if ((access_flags & Constants.ACC_INTERFACE) != 0) { + access_flags |= Constants.ACC_ABSTRACT; + } + if (((access_flags & Constants.ACC_ABSTRACT) != 0) + && ((access_flags & Constants.ACC_FINAL) != 0)) { + throw new ClassFormatException("Class can't be both final and abstract"); + } + class_name_index = file.readUnsignedShort(); + superclass_name_index = file.readUnsignedShort(); + } + + + /** + * Read constant pool entries. + * @throws IOException + * @throws ClassFormatException + */ + private final void readConstantPool() throws IOException, ClassFormatException { + constant_pool = new ConstantPool(file); + } + + + /** + * Read information about the fields of the class, i.e., its variables. + * @throws IOException + * @throws ClassFormatException + */ + private final void readFields() throws IOException, ClassFormatException { + int fields_count; + fields_count = file.readUnsignedShort(); + fields = new Field[fields_count]; + for (int i = 0; i < fields_count; i++) { + fields[i] = new Field(file, constant_pool); + } + } + + + /******************** Private utility methods **********************/ + /** + * Check whether the header of the file is ok. + * Of course, this has to be the first action on successive file reads. + * @throws IOException + * @throws ClassFormatException + */ + private final void readID() throws IOException, ClassFormatException { + int magic = 0xCAFEBABE; + if (file.readInt() != magic) { + throw new ClassFormatException(file_name + " is not a Java .class file"); + } + } + + + /** + * Read information about the interfaces implemented by this class. + * @throws IOException + * @throws ClassFormatException + */ + private final void readInterfaces() throws IOException, ClassFormatException { + int interfaces_count; + interfaces_count = file.readUnsignedShort(); + interfaces = new int[interfaces_count]; + for (int i = 0; i < interfaces_count; i++) { + interfaces[i] = file.readUnsignedShort(); + } + } + + + /** + * Read information about the methods of the class. + * @throws IOException + * @throws ClassFormatException + */ + private final void readMethods() throws IOException, ClassFormatException { + int methods_count; + methods_count = file.readUnsignedShort(); + methods = new Method[methods_count]; + for (int i = 0; i < methods_count; i++) { + methods[i] = new Method(file, constant_pool); + } + } + + + /** + * Read major and minor version of compiler which created the file. + * @throws IOException + * @throws ClassFormatException + */ + private final void readVersion() throws IOException, ClassFormatException { + minor = file.readUnsignedShort(); + major = file.readUnsignedShort(); + } +} diff --git a/src/org/apache/bcel/classfile/Code.java b/src/org/apache/bcel/classfile/Code.java new file mode 100644 index 0000000..e1b602e --- /dev/null +++ b/src/org/apache/bcel/classfile/Code.java @@ -0,0 +1,352 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class represents a chunk of Java byte code contained in a + * method. It is instantiated by the + * Attribute.readAttribute() method. A Code + * attribute contains informations about operand stack, local + * variables, byte code and the exceptions handled within this + * method. + * + * This attribute has attributes itself, namely LineNumberTable which + * is used for debugging purposes and LocalVariableTable which + * contains information about the local variables. + * + * @version $Id: Code.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Attribute + * @see CodeException + * @see LineNumberTable + * @see LocalVariableTable + */ +public final class Code extends Attribute { + + private int max_stack; // Maximum size of stack used by this method + private int max_locals; // Number of local variables + private int code_length; // Length of code in bytes + private byte[] code; // Actual byte code + private int exception_table_length; + private CodeException[] exception_table; // Table of handled exceptions + private int attributes_count; // Attributes of code: LineNumber + private Attribute[] attributes; // or LocalVariable + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use copy() for a physical copy. + */ + public Code(Code c) { + this(c.getNameIndex(), c.getLength(), c.getMaxStack(), c.getMaxLocals(), c.getCode(), c + .getExceptionTable(), c.getAttributes(), c.getConstantPool()); + } + + + /** + * @param name_index Index pointing to the name Code + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + */ + Code(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + // Initialize with some default values which will be overwritten later + this(name_index, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null, + (CodeException[]) null, (Attribute[]) null, constant_pool); + code_length = file.readInt(); + code = new byte[code_length]; // Read byte code + file.readFully(code); + /* Read exception table that contains all regions where an exception + * handler is active, i.e., a try { ... } catch() block. + */ + exception_table_length = file.readUnsignedShort(); + exception_table = new CodeException[exception_table_length]; + for (int i = 0; i < exception_table_length; i++) { + exception_table[i] = new CodeException(file); + } + /* Read all attributes, currently `LineNumberTable' and + * `LocalVariableTable' + */ + attributes_count = file.readUnsignedShort(); + attributes = new Attribute[attributes_count]; + for (int i = 0; i < attributes_count; i++) { + attributes[i] = Attribute.readAttribute(file, constant_pool); + } + /* Adjust length, because of setAttributes in this(), s.b. length + * is incorrect, because it didn't take the internal attributes + * into account yet! Very subtle bug, fixed in 3.1.1. + */ + this.length = length; + } + + + /** + * @param name_index Index pointing to the name Code + * @param length Content length in bytes + * @param max_stack Maximum size of stack + * @param max_locals Number of local variables + * @param code Actual byte code + * @param exception_table Table of handled exceptions + * @param attributes Attributes of code: LineNumber or LocalVariable + * @param constant_pool Array of constants + */ + public Code(int name_index, int length, int max_stack, int max_locals, byte[] code, + CodeException[] exception_table, Attribute[] attributes, ConstantPool constant_pool) { + super(Constants.ATTR_CODE, name_index, length, constant_pool); + this.max_stack = max_stack; + this.max_locals = max_locals; + setCode(code); + setExceptionTable(exception_table); + setAttributes(attributes); // Overwrites length! + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitCode(this); + } + + + /** + * Dump code attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + file.writeShort(max_stack); + file.writeShort(max_locals); + file.writeInt(code_length); + file.write(code, 0, code_length); + file.writeShort(exception_table_length); + for (int i = 0; i < exception_table_length; i++) { + exception_table[i].dump(file); + } + file.writeShort(attributes_count); + for (int i = 0; i < attributes_count; i++) { + attributes[i].dump(file); + } + } + + + /** + * @return Collection of code attributes. + * @see Attribute + */ + public final Attribute[] getAttributes() { + return attributes; + } + + + /** + * @return LineNumberTable of Code, if it has one + */ + public LineNumberTable getLineNumberTable() { + for (int i = 0; i < attributes_count; i++) { + if (attributes[i] instanceof LineNumberTable) { + return (LineNumberTable) attributes[i]; + } + } + return null; + } + + + /** + * @return LocalVariableTable of Code, if it has one + */ + public LocalVariableTable getLocalVariableTable() { + for (int i = 0; i < attributes_count; i++) { + if (attributes[i] instanceof LocalVariableTable) { + return (LocalVariableTable) attributes[i]; + } + } + return null; + } + + + /** + * @return Actual byte code of the method. + */ + public final byte[] getCode() { + return code; + } + + + /** + * @return Table of handled exceptions. + * @see CodeException + */ + public final CodeException[] getExceptionTable() { + return exception_table; + } + + + /** + * @return Number of local variables. + */ + public final int getMaxLocals() { + return max_locals; + } + + + /** + * @return Maximum size of stack used by this method. + */ + public final int getMaxStack() { + return max_stack; + } + + + /** + * @return the internal length of this code attribute (minus the first 6 bytes) + * and excluding all its attributes + */ + private final int getInternalLength() { + return 2 /*max_stack*/+ 2 /*max_locals*/+ 4 /*code length*/ + + code_length /*byte-code*/ + + 2 /*exception-table length*/ + + 8 * exception_table_length /* exception table */ + + 2 /* attributes count */; + } + + + /** + * @return the full size of this code attribute, minus its first 6 bytes, + * including the size of all its contained attributes + */ + private final int calculateLength() { + int len = 0; + for (int i = 0; i < attributes_count; i++) { + len += attributes[i].length + 6 /*attribute header size*/; + } + return len + getInternalLength(); + } + + + /** + * @param attributes the attributes to set for this Code + */ + public final void setAttributes( Attribute[] attributes ) { + this.attributes = attributes; + attributes_count = (attributes == null) ? 0 : attributes.length; + length = calculateLength(); // Adjust length + } + + + /** + * @param code byte code + */ + public final void setCode( byte[] code ) { + this.code = code; + code_length = (code == null) ? 0 : code.length; + } + + + /** + * @param exception_table exception table + */ + public final void setExceptionTable( CodeException[] exception_table ) { + this.exception_table = exception_table; + exception_table_length = (exception_table == null) ? 0 : exception_table.length; + } + + + /** + * @param max_locals maximum number of local variables + */ + public final void setMaxLocals( int max_locals ) { + this.max_locals = max_locals; + } + + + /** + * @param max_stack maximum stack size + */ + public final void setMaxStack( int max_stack ) { + this.max_stack = max_stack; + } + + + /** + * @return String representation of code chunk. + */ + public final String toString( boolean verbose ) { + StringBuffer buf; + buf = new StringBuffer(100); + buf.append("Code(max_stack = ").append(max_stack).append(", max_locals = ").append( + max_locals).append(", code_length = ").append(code_length).append(")\n").append( + Utility.codeToString(code, constant_pool, 0, -1, verbose)); + if (exception_table_length > 0) { + buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n"); + for (int i = 0; i < exception_table_length; i++) { + buf.append(exception_table[i].toString(constant_pool, verbose)).append("\n"); + } + } + if (attributes_count > 0) { + buf.append("\nAttribute(s) = \n"); + for (int i = 0; i < attributes_count; i++) { + buf.append(attributes[i].toString()).append("\n"); + } + } + return buf.toString(); + } + + + /** + * @return String representation of code chunk. + */ + public final String toString() { + return toString(true); + } + + + /** + * @return deep copy of this attribute + * + * @param _constant_pool the constant pool to duplicate + */ + public Attribute copy( ConstantPool _constant_pool ) { + Code c = (Code) clone(); + if (code != null) { + c.code = new byte[code.length]; + System.arraycopy(code, 0, c.code, 0, code.length); + } + c.constant_pool = _constant_pool; + c.exception_table = new CodeException[exception_table_length]; + for (int i = 0; i < exception_table_length; i++) { + c.exception_table[i] = exception_table[i].copy(); + } + c.attributes = new Attribute[attributes_count]; + for (int i = 0; i < attributes_count; i++) { + c.attributes[i] = attributes[i].copy(_constant_pool); + } + return c; + } +} diff --git a/src/org/apache/bcel/classfile/CodeException.java b/src/org/apache/bcel/classfile/CodeException.java new file mode 100644 index 0000000..1324450 --- /dev/null +++ b/src/org/apache/bcel/classfile/CodeException.java @@ -0,0 +1,214 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.Serializable; +import org.apache.bcel.Constants; + +/** + * This class represents an entry in the exception table of the Code + * attribute and is used only there. It contains a range in which a + * particular exception handler is active. + * + * @version $Id: CodeException.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Code + */ +public final class CodeException implements Cloneable, Constants, Node, Serializable { + + private int start_pc; // Range in the code the exception handler is + private int end_pc; // active. start_pc is inclusive, end_pc exclusive + private int handler_pc; /* Starting address of exception handler, i.e., + * an offset from start of code. + */ + private int catch_type; /* If this is zero the handler catches any + * exception, otherwise it points to the + * exception class which is to be caught. + */ + + + /** + * Initialize from another object. + */ + public CodeException(CodeException c) { + this(c.getStartPC(), c.getEndPC(), c.getHandlerPC(), c.getCatchType()); + } + + + /** + * Construct object from file stream. + * @param file Input stream + * @throws IOException + */ + CodeException(DataInputStream file) throws IOException { + this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file + .readUnsignedShort()); + } + + + /** + * @param start_pc Range in the code the exception handler is active, + * start_pc is inclusive while + * @param end_pc is exclusive + * @param handler_pc Starting address of exception handler, i.e., + * an offset from start of code. + * @param catch_type If zero the handler catches any + * exception, otherwise it points to the exception class which is + * to be caught. + */ + public CodeException(int start_pc, int end_pc, int handler_pc, int catch_type) { + this.start_pc = start_pc; + this.end_pc = end_pc; + this.handler_pc = handler_pc; + this.catch_type = catch_type; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitCodeException(this); + } + + + /** + * Dump code exception to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeShort(start_pc); + file.writeShort(end_pc); + file.writeShort(handler_pc); + file.writeShort(catch_type); + } + + + /** + * @return 0, if the handler catches any exception, otherwise it points to + * the exception class which is to be caught. + */ + public final int getCatchType() { + return catch_type; + } + + + /** + * @return Exclusive end index of the region where the handler is active. + */ + public final int getEndPC() { + return end_pc; + } + + + /** + * @return Starting address of exception handler, relative to the code. + */ + public final int getHandlerPC() { + return handler_pc; + } + + + /** + * @return Inclusive start index of the region where the handler is active. + */ + public final int getStartPC() { + return start_pc; + } + + + /** + * @param catch_type the type of exception that is caught + */ + public final void setCatchType( int catch_type ) { + this.catch_type = catch_type; + } + + + /** + * @param end_pc end of handled block + */ + public final void setEndPC( int end_pc ) { + this.end_pc = end_pc; + } + + + /** + * @param handler_pc where the actual code is + */ + public final void setHandlerPC( int handler_pc ) { + this.handler_pc = handler_pc; + } + + + /** + * @param start_pc start of handled block + */ + public final void setStartPC( int start_pc ) { + this.start_pc = start_pc; + } + + + /** + * @return String representation. + */ + public final String toString() { + return "CodeException(start_pc = " + start_pc + ", end_pc = " + end_pc + ", handler_pc = " + + handler_pc + ", catch_type = " + catch_type + ")"; + } + + + /** + * @return String representation. + */ + public final String toString( ConstantPool cp, boolean verbose ) { + String str; + if (catch_type == 0) { + str = "(0)"; + } else { + str = Utility.compactClassName(cp.getConstantString(catch_type, CONSTANT_Class), false) + + (verbose ? "(" + catch_type + ")" : ""); + } + return start_pc + "\t" + end_pc + "\t" + handler_pc + "\t" + str; + } + + + public final String toString( ConstantPool cp ) { + return toString(cp, true); + } + + + /** + * @return deep copy of this object + */ + public CodeException copy() { + try { + return (CodeException) clone(); + } catch (CloneNotSupportedException e) { + } + return null; + } +} diff --git a/src/org/apache/bcel/classfile/Constant.java b/src/org/apache/bcel/classfile/Constant.java new file mode 100644 index 0000000..5b0dda6 --- /dev/null +++ b/src/org/apache/bcel/classfile/Constant.java @@ -0,0 +1,188 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.Serializable; +import org.apache.bcel.Constants; +import org.apache.bcel.util.BCELComparator; + +/** + * Abstract superclass for classes to represent the different constant types + * in the constant pool of a class file. The classes keep closely to + * the JVM specification. + * + * @version $Id: Constant.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class Constant implements Cloneable, Node, Serializable { + + private static BCELComparator _cmp = new BCELComparator() { + + public boolean equals( Object o1, Object o2 ) { + Constant THIS = (Constant) o1; + Constant THAT = (Constant) o2; + return THIS.toString().equals(THAT.toString()); + } + + + public int hashCode( Object o ) { + Constant THIS = (Constant) o; + return THIS.toString().hashCode(); + } + }; + /* In fact this tag is redundant since we can distinguish different + * `Constant' objects by their type, i.e., via `instanceof'. In some + * places we will use the tag for switch()es anyway. + * + * First, we want match the specification as closely as possible. Second we + * need the tag as an index to select the corresponding class name from the + * `CONSTANT_NAMES' array. + */ + protected byte tag; + + + Constant(byte tag) { + this.tag = tag; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public abstract void accept( Visitor v ); + + + public abstract void dump( DataOutputStream file ) throws IOException; + + + /** + * @return Tag of constant, i.e., its type. No setTag() method to avoid + * confusion. + */ + public final byte getTag() { + return tag; + } + + + /** + * @return String representation. + */ + public String toString() { + return Constants.CONSTANT_NAMES[tag] + "[" + tag + "]"; + } + + + /** + * @return deep copy of this constant + */ + public Constant copy() { + try { + return (Constant) super.clone(); + } catch (CloneNotSupportedException e) { + } + return null; + } + + + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + + /** + * Read one constant from the given file, the type depends on a tag byte. + * + * @param file Input stream + * @return Constant object + */ + static final Constant readConstant( DataInputStream file ) throws IOException, + ClassFormatException { + byte b = file.readByte(); // Read tag byte + switch (b) { + case Constants.CONSTANT_Class: + return new ConstantClass(file); + case Constants.CONSTANT_Fieldref: + return new ConstantFieldref(file); + case Constants.CONSTANT_Methodref: + return new ConstantMethodref(file); + case Constants.CONSTANT_InterfaceMethodref: + return new ConstantInterfaceMethodref(file); + case Constants.CONSTANT_String: + return new ConstantString(file); + case Constants.CONSTANT_Integer: + return new ConstantInteger(file); + case Constants.CONSTANT_Float: + return new ConstantFloat(file); + case Constants.CONSTANT_Long: + return new ConstantLong(file); + case Constants.CONSTANT_Double: + return new ConstantDouble(file); + case Constants.CONSTANT_NameAndType: + return new ConstantNameAndType(file); + case Constants.CONSTANT_Utf8: + return new ConstantUtf8(file); + default: + throw new ClassFormatException("Invalid byte tag in constant pool: " + b); + } + } + + + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return _cmp; + } + + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator( BCELComparator comparator ) { + _cmp = comparator; + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default two Constant objects are said to be equal when + * the result of toString() is equal. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals( Object obj ) { + return _cmp.equals(this, obj); + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default return the hashcode of the result of toString(). + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return _cmp.hashCode(this); + } +} diff --git a/src/org/apache/bcel/classfile/ConstantCP.java b/src/org/apache/bcel/classfile/ConstantCP.java new file mode 100644 index 0000000..9f3377a --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantCP.java @@ -0,0 +1,131 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * Abstract super class for Fieldref and Methodref constants. + * + * @version $Id: ConstantCP.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see ConstantFieldref + * @see ConstantMethodref + * @see ConstantInterfaceMethodref + */ +public abstract class ConstantCP extends Constant { + + /** References to the constants containing the class and the field signature + */ + protected int class_index, name_and_type_index; + + + /** + * Initialize from another object. + */ + public ConstantCP(ConstantCP c) { + this(c.getTag(), c.getClassIndex(), c.getNameAndTypeIndex()); + } + + + /** + * Initialize instance from file data. + * + * @param tag Constant type tag + * @param file Input stream + * @throws IOException + */ + ConstantCP(byte tag, DataInputStream file) throws IOException { + this(tag, file.readUnsignedShort(), file.readUnsignedShort()); + } + + + /** + * @param class_index Reference to the class containing the field + * @param name_and_type_index and the field signature + */ + protected ConstantCP(byte tag, int class_index, int name_and_type_index) { + super(tag); + this.class_index = class_index; + this.name_and_type_index = name_and_type_index; + } + + + /** + * Dump constant field reference to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeByte(tag); + file.writeShort(class_index); + file.writeShort(name_and_type_index); + } + + + /** + * @return Reference (index) to class this field or method belongs to. + */ + public final int getClassIndex() { + return class_index; + } + + + /** + * @return Reference (index) to signature of the field. + */ + public final int getNameAndTypeIndex() { + return name_and_type_index; + } + + + /** + * @param class_index points to Constant_class + */ + public final void setClassIndex( int class_index ) { + this.class_index = class_index; + } + + + /** + * @return Class this field belongs to. + */ + public String getClass( ConstantPool cp ) { + return cp.constantToString(class_index, Constants.CONSTANT_Class); + } + + + /** + * @param name_and_type_index points to Constant_NameAndType + */ + public final void setNameAndTypeIndex( int name_and_type_index ) { + this.name_and_type_index = name_and_type_index; + } + + + /** + * @return String representation. + */ + public final String toString() { + return super.toString() + "(class_index = " + class_index + ", name_and_type_index = " + + name_and_type_index + ")"; + } +} diff --git a/src/org/apache/bcel/classfile/ConstantClass.java b/src/org/apache/bcel/classfile/ConstantClass.java new file mode 100644 index 0000000..adddf3c --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantClass.java @@ -0,0 +1,128 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from the abstract + * Constant class + * and represents a reference to a (external) class. + * + * @version $Id: ConstantClass.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constant + */ +public final class ConstantClass extends Constant implements ConstantObject { + + private int name_index; // Identical to ConstantString except for the name + + + /** + * Initialize from another object. + */ + public ConstantClass(ConstantClass c) { + this(c.getNameIndex()); + } + + + /** + * Initialize instance from file data. + * + * @param file Input stream + * @throws IOException + */ + ConstantClass(DataInputStream file) throws IOException { + this(file.readUnsignedShort()); + } + + + /** + * @param name_index Name index in constant pool. Should refer to a + * ConstantUtf8. + */ + public ConstantClass(int name_index) { + super(Constants.CONSTANT_Class); + this.name_index = name_index; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantClass(this); + } + + + /** + * Dump constant class to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeByte(tag); + file.writeShort(name_index); + } + + + /** + * @return Name index in constant pool of class name. + */ + public final int getNameIndex() { + return name_index; + } + + + /** + * @param name_index the name index in the constant pool of this Constant Class + */ + public final void setNameIndex( int name_index ) { + this.name_index = name_index; + } + + + /** @return String object + */ + public Object getConstantValue( ConstantPool cp ) { + Constant c = cp.getConstant(name_index, Constants.CONSTANT_Utf8); + return ((ConstantUtf8) c).getBytes(); + } + + + /** @return dereferenced string + */ + public String getBytes( ConstantPool cp ) { + return (String) getConstantValue(cp); + } + + + /** + * @return String representation. + */ + public final String toString() { + return super.toString() + "(name_index = " + name_index + ")"; + } +} diff --git a/src/org/apache/bcel/classfile/ConstantDouble.java b/src/org/apache/bcel/classfile/ConstantDouble.java new file mode 100644 index 0000000..80e96e4 --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantDouble.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from the abstract + * Constant class + * and represents a reference to a Double object. + * + * @version $Id: ConstantDouble.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constant + */ +public final class ConstantDouble extends Constant implements ConstantObject { + + private double bytes; + + + /** + * @param bytes Data + */ + public ConstantDouble(double bytes) { + super(Constants.CONSTANT_Double); + this.bytes = bytes; + } + + + /** + * Initialize from another object. + */ + public ConstantDouble(ConstantDouble c) { + this(c.getBytes()); + } + + + /** + * Initialize instance from file data. + * + * @param file Input stream + * @throws IOException + */ + ConstantDouble(DataInputStream file) throws IOException { + this(file.readDouble()); + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantDouble(this); + } + + + /** + * Dump constant double to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeByte(tag); + file.writeDouble(bytes); + } + + + /** + * @return data, i.e., 8 bytes. + */ + public final double getBytes() { + return bytes; + } + + + /** + * @param bytes the raw bytes that represent the double value + */ + public final void setBytes( double bytes ) { + this.bytes = bytes; + } + + + /** + * @return String representation. + */ + public final String toString() { + return super.toString() + "(bytes = " + bytes + ")"; + } + + + /** @return Double object + */ + public Object getConstantValue( ConstantPool cp ) { + return new Double(bytes); + } +} diff --git a/src/org/apache/bcel/classfile/ConstantFieldref.java b/src/org/apache/bcel/classfile/ConstantFieldref.java new file mode 100644 index 0000000..71df99c --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantFieldref.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class represents a constant pool reference to a field. + * + * @version $Id: ConstantFieldref.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class ConstantFieldref extends ConstantCP { + + /** + * Initialize from another object. + */ + public ConstantFieldref(ConstantFieldref c) { + super(Constants.CONSTANT_Fieldref, c.getClassIndex(), c.getNameAndTypeIndex()); + } + + + /** + * Initialize instance from file data. + * + * @param file input stream + * @throws IOException + */ + ConstantFieldref(DataInputStream file) throws IOException { + super(Constants.CONSTANT_Fieldref, file); + } + + + /** + * @param class_index Reference to the class containing the Field + * @param name_and_type_index and the Field signature + */ + public ConstantFieldref(int class_index, int name_and_type_index) { + super(Constants.CONSTANT_Fieldref, class_index, name_and_type_index); + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of Fields, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantFieldref(this); + } +} diff --git a/src/org/apache/bcel/classfile/ConstantFloat.java b/src/org/apache/bcel/classfile/ConstantFloat.java new file mode 100644 index 0000000..8c18fef --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantFloat.java @@ -0,0 +1,120 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from the abstract + * Constant class + * and represents a reference to a float object. + * + * @version $Id: ConstantFloat.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constant + */ +public final class ConstantFloat extends Constant implements ConstantObject { + + private float bytes; + + + /** + * @param bytes Data + */ + public ConstantFloat(float bytes) { + super(Constants.CONSTANT_Float); + this.bytes = bytes; + } + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + public ConstantFloat(ConstantFloat c) { + this(c.getBytes()); + } + + + /** + * Initialize instance from file data. + * + * @param file Input stream + * @throws IOException + */ + ConstantFloat(DataInputStream file) throws IOException { + this(file.readFloat()); + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantFloat(this); + } + + + /** + * Dump constant float to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeByte(tag); + file.writeFloat(bytes); + } + + + /** + * @return data, i.e., 4 bytes. + */ + public final float getBytes() { + return bytes; + } + + + /** + * @param bytes the raw bytes that represent this float + */ + public final void setBytes( float bytes ) { + this.bytes = bytes; + } + + + /** + * @return String representation. + */ + public final String toString() { + return super.toString() + "(bytes = " + bytes + ")"; + } + + + /** @return Float object + */ + public Object getConstantValue( ConstantPool cp ) { + return new Float(bytes); + } +} diff --git a/src/org/apache/bcel/classfile/ConstantInteger.java b/src/org/apache/bcel/classfile/ConstantInteger.java new file mode 100644 index 0000000..bdd21e2 --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantInteger.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from the abstract + * Constant class + * and represents a reference to an int object. + * + * @version $Id: ConstantInteger.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constant + */ +public final class ConstantInteger extends Constant implements ConstantObject { + + private int bytes; + + + /** + * @param bytes Data + */ + public ConstantInteger(int bytes) { + super(Constants.CONSTANT_Integer); + this.bytes = bytes; + } + + + /** + * Initialize from another object. + */ + public ConstantInteger(ConstantInteger c) { + this(c.getBytes()); + } + + + /** + * Initialize instance from file data. + * + * @param file Input stream + * @throws IOException + */ + ConstantInteger(DataInputStream file) throws IOException { + this(file.readInt()); + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantInteger(this); + } + + + /** + * Dump constant integer to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeByte(tag); + file.writeInt(bytes); + } + + + /** + * @return data, i.e., 4 bytes. + */ + public final int getBytes() { + return bytes; + } + + + /** + * @param bytes the raw bytes that represent this integer + */ + public final void setBytes( int bytes ) { + this.bytes = bytes; + } + + + /** + * @return String representation. + */ + public final String toString() { + return super.toString() + "(bytes = " + bytes + ")"; + } + + + /** @return Integer object + */ + public Object getConstantValue( ConstantPool cp ) { + return new Integer(bytes); + } +} diff --git a/src/org/apache/bcel/classfile/ConstantInterfaceMethodref.java b/src/org/apache/bcel/classfile/ConstantInterfaceMethodref.java new file mode 100644 index 0000000..ba3a96a --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantInterfaceMethodref.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class represents a constant pool reference to an interface method. + * + * @version $Id: ConstantInterfaceMethodref.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class ConstantInterfaceMethodref extends ConstantCP { + + /** + * Initialize from another object. + */ + public ConstantInterfaceMethodref(ConstantInterfaceMethodref c) { + super(Constants.CONSTANT_InterfaceMethodref, c.getClassIndex(), c.getNameAndTypeIndex()); + } + + + /** + * Initialize instance from file data. + * + * @param file input stream + * @throws IOException + */ + ConstantInterfaceMethodref(DataInputStream file) throws IOException { + super(Constants.CONSTANT_InterfaceMethodref, file); + } + + + /** + * @param class_index Reference to the class containing the method + * @param name_and_type_index and the method signature + */ + public ConstantInterfaceMethodref(int class_index, int name_and_type_index) { + super(Constants.CONSTANT_InterfaceMethodref, class_index, name_and_type_index); + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantInterfaceMethodref(this); + } +} diff --git a/src/org/apache/bcel/classfile/ConstantLong.java b/src/org/apache/bcel/classfile/ConstantLong.java new file mode 100644 index 0000000..e0d475d --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantLong.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from the abstract + * Constant class + * and represents a reference to a long object. + * + * @version $Id: ConstantLong.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constant + */ +public final class ConstantLong extends Constant implements ConstantObject { + + private long bytes; + + + /** + * @param bytes Data + */ + public ConstantLong(long bytes) { + super(Constants.CONSTANT_Long); + this.bytes = bytes; + } + + + /** + * Initialize from another object. + */ + public ConstantLong(ConstantLong c) { + this(c.getBytes()); + } + + + /** + * Initialize instance from file data. + * + * @param file Input stream + * @throws IOException + */ + ConstantLong(DataInputStream file) throws IOException { + this(file.readLong()); + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantLong(this); + } + + + /** + * Dump constant long to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeByte(tag); + file.writeLong(bytes); + } + + + /** + * @return data, i.e., 8 bytes. + */ + public final long getBytes() { + return bytes; + } + + + /** + * @param bytes thr raw bytes that represent this long + */ + public final void setBytes( long bytes ) { + this.bytes = bytes; + } + + + /** + * @return String representation. + */ + public final String toString() { + return super.toString() + "(bytes = " + bytes + ")"; + } + + + /** @return Long object + */ + public Object getConstantValue( ConstantPool cp ) { + return new Long(bytes); + } +} diff --git a/src/org/apache/bcel/classfile/ConstantMethodref.java b/src/org/apache/bcel/classfile/ConstantMethodref.java new file mode 100644 index 0000000..0991238 --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantMethodref.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class represents a constant pool reference to a method. + * + * @version $Id: ConstantMethodref.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class ConstantMethodref extends ConstantCP { + + /** + * Initialize from another object. + */ + public ConstantMethodref(ConstantMethodref c) { + super(Constants.CONSTANT_Methodref, c.getClassIndex(), c.getNameAndTypeIndex()); + } + + + /** + * Initialize instance from file data. + * + * @param file input stream + * @throws IOException + */ + ConstantMethodref(DataInputStream file) throws IOException { + super(Constants.CONSTANT_Methodref, file); + } + + + /** + * @param class_index Reference to the class containing the method + * @param name_and_type_index and the method signature + */ + public ConstantMethodref(int class_index, int name_and_type_index) { + super(Constants.CONSTANT_Methodref, class_index, name_and_type_index); + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantMethodref(this); + } +} diff --git a/src/org/apache/bcel/classfile/ConstantNameAndType.java b/src/org/apache/bcel/classfile/ConstantNameAndType.java new file mode 100644 index 0000000..01a833e --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantNameAndType.java @@ -0,0 +1,148 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from the abstract + * Constant class + * and represents a reference to the name and signature + * of a field or method. + * + * @version $Id: ConstantNameAndType.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constant + */ +public final class ConstantNameAndType extends Constant { + + private int name_index; // Name of field/method + private int signature_index; // and its signature. + + + /** + * Initialize from another object. + */ + public ConstantNameAndType(ConstantNameAndType c) { + this(c.getNameIndex(), c.getSignatureIndex()); + } + + + /** + * Initialize instance from file data. + * + * @param file Input stream + * @throws IOException + */ + ConstantNameAndType(DataInputStream file) throws IOException { + this(file.readUnsignedShort(), file.readUnsignedShort()); + } + + + /** + * @param name_index Name of field/method + * @param signature_index and its signature + */ + public ConstantNameAndType(int name_index, int signature_index) { + super(Constants.CONSTANT_NameAndType); + this.name_index = name_index; + this.signature_index = signature_index; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantNameAndType(this); + } + + + /** + * Dump name and signature index to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeByte(tag); + file.writeShort(name_index); + file.writeShort(signature_index); + } + + + /** + * @return Name index in constant pool of field/method name. + */ + public final int getNameIndex() { + return name_index; + } + + + /** @return name + */ + public final String getName( ConstantPool cp ) { + return cp.constantToString(getNameIndex(), Constants.CONSTANT_Utf8); + } + + + /** + * @return Index in constant pool of field/method signature. + */ + public final int getSignatureIndex() { + return signature_index; + } + + + /** @return signature + */ + public final String getSignature( ConstantPool cp ) { + return cp.constantToString(getSignatureIndex(), Constants.CONSTANT_Utf8); + } + + + /** + * @param name_index the name index of this constant + */ + public final void setNameIndex( int name_index ) { + this.name_index = name_index; + } + + + /** + * @param signature_index the signature index in the constant pool of this type + */ + public final void setSignatureIndex( int signature_index ) { + this.signature_index = signature_index; + } + + + /** + * @return String representation + */ + public final String toString() { + return super.toString() + "(name_index = " + name_index + ", signature_index = " + + signature_index + ")"; + } +} diff --git a/src/org/apache/bcel/classfile/ConstantObject.java b/src/org/apache/bcel/classfile/ConstantObject.java new file mode 100644 index 0000000..38917af --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantObject.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +/** + * This interface denotes those constants that have a "natural" value, + * such as ConstantLong, ConstantString, etc.. + * + * @version $Id: ConstantObject.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constant + */ +public interface ConstantObject { + + /** @return object representing the constant, e.g., Long for ConstantLong + */ + public abstract Object getConstantValue( ConstantPool cp ); +} diff --git a/src/org/apache/bcel/classfile/ConstantPool.java b/src/org/apache/bcel/classfile/ConstantPool.java new file mode 100644 index 0000000..9b92d63 --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantPool.java @@ -0,0 +1,353 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.Serializable; +import org.apache.bcel.Constants; + +/** + * This class represents the constant pool, i.e., a table of constants, of + * a parsed classfile. It may contain null references, due to the JVM + * specification that skips an entry after an 8-byte constant (double, + * long) entry. Those interested in generating constant pools + * programatically should see + * ConstantPoolGen. + + * @version $Id: ConstantPool.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @see Constant + * @see org.apache.bcel.generic.ConstantPoolGen + * @author M. Dahm + */ +public class ConstantPool implements Cloneable, Node, Serializable { + + private int constant_pool_count; + private Constant[] constant_pool; + + + /** + * @param constant_pool Array of constants + */ + public ConstantPool(Constant[] constant_pool) { + setConstantPool(constant_pool); + } + + + /** + * Read constants from given file stream. + * + * @param file Input stream + * @throws IOException + * @throws ClassFormatException + */ + ConstantPool(DataInputStream file) throws IOException, ClassFormatException { + byte tag; + constant_pool_count = file.readUnsignedShort(); + constant_pool = new Constant[constant_pool_count]; + /* constant_pool[0] is unused by the compiler and may be used freely + * by the implementation. + */ + for (int i = 1; i < constant_pool_count; i++) { + constant_pool[i] = Constant.readConstant(file); + /* Quote from the JVM specification: + * "All eight byte constants take up two spots in the constant pool. + * If this is the n'th byte in the constant pool, then the next item + * will be numbered n+2" + * + * Thus we have to increment the index counter. + */ + tag = constant_pool[i].getTag(); + if ((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long)) { + i++; + } + } + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantPool(this); + } + + + /** + * Resolve constant to a string representation. + * + * @param c Constant to be printed + * @return String representation + */ + public String constantToString( Constant c ) throws ClassFormatException { + String str; + int i; + byte tag = c.getTag(); + switch (tag) { + case Constants.CONSTANT_Class: + i = ((ConstantClass) c).getNameIndex(); + c = getConstant(i, Constants.CONSTANT_Utf8); + str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); + break; + case Constants.CONSTANT_String: + i = ((ConstantString) c).getStringIndex(); + c = getConstant(i, Constants.CONSTANT_Utf8); + str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\""; + break; + case Constants.CONSTANT_Utf8: + str = ((ConstantUtf8) c).getBytes(); + break; + case Constants.CONSTANT_Double: + str = "" + ((ConstantDouble) c).getBytes(); + break; + case Constants.CONSTANT_Float: + str = "" + ((ConstantFloat) c).getBytes(); + break; + case Constants.CONSTANT_Long: + str = "" + ((ConstantLong) c).getBytes(); + break; + case Constants.CONSTANT_Integer: + str = "" + ((ConstantInteger) c).getBytes(); + break; + case Constants.CONSTANT_NameAndType: + str = (constantToString(((ConstantNameAndType) c).getNameIndex(), + Constants.CONSTANT_Utf8) + + " " + constantToString(((ConstantNameAndType) c).getSignatureIndex(), + Constants.CONSTANT_Utf8)); + break; + case Constants.CONSTANT_InterfaceMethodref: + case Constants.CONSTANT_Methodref: + case Constants.CONSTANT_Fieldref: + str = (constantToString(((ConstantCP) c).getClassIndex(), Constants.CONSTANT_Class) + + "." + constantToString(((ConstantCP) c).getNameAndTypeIndex(), + Constants.CONSTANT_NameAndType)); + break; + default: // Never reached + throw new RuntimeException("Unknown constant type " + tag); + } + return str; + } + + + private static final String escape( String str ) { + int len = str.length(); + StringBuffer buf = new StringBuffer(len + 5); + char[] ch = str.toCharArray(); + for (int i = 0; i < len; i++) { + switch (ch[i]) { + case '\n': + buf.append("\\n"); + break; + case '\r': + buf.append("\\r"); + break; + case '\t': + buf.append("\\t"); + break; + case '\b': + buf.append("\\b"); + break; + case '"': + buf.append("\\\""); + break; + default: + buf.append(ch[i]); + } + } + return buf.toString(); + } + + + /** + * Retrieve constant at `index' from constant pool and resolve it to + * a string representation. + * + * @param index of constant in constant pool + * @param tag expected type + * @return String representation + */ + public String constantToString( int index, byte tag ) throws ClassFormatException { + Constant c = getConstant(index, tag); + return constantToString(c); + } + + + /** + * Dump constant pool to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public void dump( DataOutputStream file ) throws IOException { + file.writeShort(constant_pool_count); + for (int i = 1; i < constant_pool_count; i++) { + if (constant_pool[i] != null) { + constant_pool[i].dump(file); + } + } + } + + + /** + * Get constant from constant pool. + * + * @param index Index in constant pool + * @return Constant value + * @see Constant + */ + public Constant getConstant( int index ) { + if (index >= constant_pool.length || index < 0) { + throw new ClassFormatException("Invalid constant pool reference: " + index + + ". Constant pool size is: " + constant_pool.length); + } + return constant_pool[index]; + } + + + /** + * Get constant from constant pool and check whether it has the + * expected type. + * + * @param index Index in constant pool + * @param tag Tag of expected constant, i.e., its type + * @return Constant value + * @see Constant + * @throws ClassFormatException + */ + public Constant getConstant( int index, byte tag ) throws ClassFormatException { + Constant c; + c = getConstant(index); + if (c == null) { + throw new ClassFormatException("Constant pool at index " + index + " is null."); + } + if (c.getTag() != tag) { + throw new ClassFormatException("Expected class `" + Constants.CONSTANT_NAMES[tag] + + "' at index " + index + " and got " + c); + } + return c; + } + + + /** + * @return Array of constants. + * @see Constant + */ + public Constant[] getConstantPool() { + return constant_pool; + } + + + /** + * Get string from constant pool and bypass the indirection of + * `ConstantClass' and `ConstantString' objects. I.e. these classes have + * an index field that points to another entry of the constant pool of + * type `ConstantUtf8' which contains the real data. + * + * @param index Index in constant pool + * @param tag Tag of expected constant, either ConstantClass or ConstantString + * @return Contents of string reference + * @see ConstantClass + * @see ConstantString + * @throws ClassFormatException + */ + public String getConstantString( int index, byte tag ) throws ClassFormatException { + Constant c; + int i; + c = getConstant(index, tag); + /* This switch() is not that elegant, since the two classes have the + * same contents, they just differ in the name of the index + * field variable. + * But we want to stick to the JVM naming conventions closely though + * we could have solved these more elegantly by using the same + * variable name or by subclassing. + */ + switch (tag) { + case Constants.CONSTANT_Class: + i = ((ConstantClass) c).getNameIndex(); + break; + case Constants.CONSTANT_String: + i = ((ConstantString) c).getStringIndex(); + break; + default: + throw new RuntimeException("getConstantString called with illegal tag " + tag); + } + // Finally get the string from the constant pool + c = getConstant(i, Constants.CONSTANT_Utf8); + return ((ConstantUtf8) c).getBytes(); + } + + + /** + * @return Length of constant pool. + */ + public int getLength() { + return constant_pool_count; + } + + + /** + * @param constant Constant to set + */ + public void setConstant( int index, Constant constant ) { + constant_pool[index] = constant; + } + + + /** + * @param constant_pool + */ + public void setConstantPool( Constant[] constant_pool ) { + this.constant_pool = constant_pool; + constant_pool_count = (constant_pool == null) ? 0 : constant_pool.length; + } + + + /** + * @return String representation. + */ + public String toString() { + StringBuffer buf = new StringBuffer(); + for (int i = 1; i < constant_pool_count; i++) { + buf.append(i).append(")").append(constant_pool[i]).append("\n"); + } + return buf.toString(); + } + + + /** + * @return deep copy of this constant pool + */ + public ConstantPool copy() { + ConstantPool c = null; + try { + c = (ConstantPool) clone(); + c.constant_pool = new Constant[constant_pool_count]; + for (int i = 1; i < constant_pool_count; i++) { + if (constant_pool[i] != null) { + c.constant_pool[i] = constant_pool[i].copy(); + } + } + } catch (CloneNotSupportedException e) { + } + return c; + } +} diff --git a/src/org/apache/bcel/classfile/ConstantString.java b/src/org/apache/bcel/classfile/ConstantString.java new file mode 100644 index 0000000..c9474dd --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantString.java @@ -0,0 +1,127 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from the abstract + * Constant class + * and represents a reference to a String object. + * + * @version $Id: ConstantString.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constant + */ +public final class ConstantString extends Constant implements ConstantObject { + + private int string_index; // Identical to ConstantClass except for this name + + + /** + * Initialize from another object. + */ + public ConstantString(ConstantString c) { + this(c.getStringIndex()); + } + + + /** + * Initialize instance from file data. + * + * @param file Input stream + * @throws IOException + */ + ConstantString(DataInputStream file) throws IOException { + this(file.readUnsignedShort()); + } + + + /** + * @param string_index Index of Constant_Utf8 in constant pool + */ + public ConstantString(int string_index) { + super(Constants.CONSTANT_String); + this.string_index = string_index; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantString(this); + } + + + /** + * Dump constant field reference to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeByte(tag); + file.writeShort(string_index); + } + + + /** + * @return Index in constant pool of the string (ConstantUtf8). + */ + public final int getStringIndex() { + return string_index; + } + + + /** + * @param string_index the index into the constant of the string value + */ + public final void setStringIndex( int string_index ) { + this.string_index = string_index; + } + + + /** + * @return String representation. + */ + public final String toString() { + return super.toString() + "(string_index = " + string_index + ")"; + } + + + /** @return String object + */ + public Object getConstantValue( ConstantPool cp ) { + Constant c = cp.getConstant(string_index, Constants.CONSTANT_Utf8); + return ((ConstantUtf8) c).getBytes(); + } + + + /** @return dereferenced string + */ + public String getBytes( ConstantPool cp ) { + return (String) getConstantValue(cp); + } +} diff --git a/src/org/apache/bcel/classfile/ConstantUtf8.java b/src/org/apache/bcel/classfile/ConstantUtf8.java new file mode 100644 index 0000000..f30e0d4 --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantUtf8.java @@ -0,0 +1,116 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from the abstract + * Constant class + * and represents a reference to a Utf8 encoded string. + * + * @version $Id: ConstantUtf8.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constant + */ +public final class ConstantUtf8 extends Constant { + + private String bytes; + + + /** + * Initialize from another object. + */ + public ConstantUtf8(ConstantUtf8 c) { + this(c.getBytes()); + } + + + /** + * Initialize instance from file data. + * + * @param file Input stream + * @throws IOException + */ + ConstantUtf8(DataInputStream file) throws IOException { + super(Constants.CONSTANT_Utf8); + bytes = file.readUTF(); + } + + + /** + * @param bytes Data + */ + public ConstantUtf8(String bytes) { + super(Constants.CONSTANT_Utf8); + if (bytes == null) { + throw new IllegalArgumentException("bytes must not be null!"); + } + this.bytes = bytes; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantUtf8(this); + } + + + /** + * Dump String in Utf8 format to file stream. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeByte(tag); + file.writeUTF(bytes); + } + + + /** + * @return Data converted to string. + */ + public final String getBytes() { + return bytes; + } + + + /** + * @param bytes the raw bytes of this Utf-8 + */ + public final void setBytes( String bytes ) { + this.bytes = bytes; + } + + + /** + * @return String representation + */ + public final String toString() { + return super.toString() + "(\"" + Utility.replace(bytes, "\n", "\\n") + "\")"; + } +} diff --git a/src/org/apache/bcel/classfile/ConstantValue.java b/src/org/apache/bcel/classfile/ConstantValue.java new file mode 100644 index 0000000..b0d89da --- /dev/null +++ b/src/org/apache/bcel/classfile/ConstantValue.java @@ -0,0 +1,155 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from Attribute and represents a constant + * value, i.e., a default value for initializing a class field. + * This class is instantiated by the Attribute.readAttribute() method. + * + * @version $Id: ConstantValue.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Attribute + */ +public final class ConstantValue extends Attribute { + + private int constantvalue_index; + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + public ConstantValue(ConstantValue c) { + this(c.getNameIndex(), c.getLength(), c.getConstantValueIndex(), c.getConstantPool()); + } + + + /** + * Construct object from file stream. + * @param name_index Name index in constant pool + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + ConstantValue(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, file.readUnsignedShort(), constant_pool); + } + + + /** + * @param name_index Name index in constant pool + * @param length Content length in bytes + * @param constantvalue_index Index in constant pool + * @param constant_pool Array of constants + */ + public ConstantValue(int name_index, int length, int constantvalue_index, + ConstantPool constant_pool) { + super(Constants.ATTR_CONSTANT_VALUE, name_index, length, constant_pool); + this.constantvalue_index = constantvalue_index; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitConstantValue(this); + } + + + /** + * Dump constant value attribute to file stream on binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + file.writeShort(constantvalue_index); + } + + + /** + * @return Index in constant pool of constant value. + */ + public final int getConstantValueIndex() { + return constantvalue_index; + } + + + /** + * @param constantvalue_index the index info the constant pool of this constant value + */ + public final void setConstantValueIndex( int constantvalue_index ) { + this.constantvalue_index = constantvalue_index; + } + + + /** + * @return String representation of constant value. + */ + public final String toString() { + Constant c = constant_pool.getConstant(constantvalue_index); + String buf; + int i; + // Print constant to string depending on its type + switch (c.getTag()) { + case Constants.CONSTANT_Long: + buf = "" + ((ConstantLong) c).getBytes(); + break; + case Constants.CONSTANT_Float: + buf = "" + ((ConstantFloat) c).getBytes(); + break; + case Constants.CONSTANT_Double: + buf = "" + ((ConstantDouble) c).getBytes(); + break; + case Constants.CONSTANT_Integer: + buf = "" + ((ConstantInteger) c).getBytes(); + break; + case Constants.CONSTANT_String: + i = ((ConstantString) c).getStringIndex(); + c = constant_pool.getConstant(i, Constants.CONSTANT_Utf8); + buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\""; + break; + default: + throw new IllegalStateException("Type of ConstValue invalid: " + c); + } + return buf; + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + ConstantValue c = (ConstantValue) clone(); + c.constant_pool = _constant_pool; + return c; + } +} diff --git a/src/org/apache/bcel/classfile/Deprecated.java b/src/org/apache/bcel/classfile/Deprecated.java new file mode 100644 index 0000000..50529fb --- /dev/null +++ b/src/org/apache/bcel/classfile/Deprecated.java @@ -0,0 +1,140 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from Attribute and denotes that this is a + * deprecated method. + * It is instantiated from the Attribute.readAttribute() method. + * + * @version $Id: Deprecated.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Attribute + */ +public final class Deprecated extends Attribute { + + private byte[] bytes; + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + public Deprecated(Deprecated c) { + this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool()); + } + + + /** + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param bytes Attribute contents + * @param constant_pool Array of constants + */ + public Deprecated(int name_index, int length, byte[] bytes, ConstantPool constant_pool) { + super(Constants.ATTR_DEPRECATED, name_index, length, constant_pool); + this.bytes = bytes; + } + + + /** + * Construct object from file stream. + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + Deprecated(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, (byte[]) null, constant_pool); + if (length > 0) { + bytes = new byte[length]; + file.readFully(bytes); + System.err.println("Deprecated attribute with length > 0"); + } + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitDeprecated(this); + } + + + /** + * Dump source file attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + if (length > 0) { + file.write(bytes, 0, length); + } + } + + + /** + * @return data bytes. + */ + public final byte[] getBytes() { + return bytes; + } + + + /** + * @param bytes the raw bytes that represents this byte array + */ + public final void setBytes( byte[] bytes ) { + this.bytes = bytes; + } + + + /** + * @return attribute name + */ + public final String toString() { + return Constants.ATTRIBUTE_NAMES[Constants.ATTR_DEPRECATED]; + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + Deprecated c = (Deprecated) clone(); + if (bytes != null) { + c.bytes = new byte[bytes.length]; + System.arraycopy(bytes, 0, c.bytes, 0, bytes.length); + } + c.constant_pool = _constant_pool; + return c; + } +} diff --git a/src/org/apache/bcel/classfile/DescendingVisitor.java b/src/org/apache/bcel/classfile/DescendingVisitor.java new file mode 100644 index 0000000..dae5111 --- /dev/null +++ b/src/org/apache/bcel/classfile/DescendingVisitor.java @@ -0,0 +1,356 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.util.Stack; + +/** + * Traverses a JavaClass with another Visitor object 'piggy-backed' + * that is applied to all components of a JavaClass object. I.e. this + * class supplies the traversal strategy, other classes can make use + * of it. + * + * @version $Id: DescendingVisitor.java 388707 2006-03-25 05:40:28Z tcurdt $ + * @author M. Dahm + */ +public class DescendingVisitor implements Visitor { + + private JavaClass clazz; + private Visitor visitor; + private Stack stack = new Stack(); + + + /** @return container of current entitity, i.e., predecessor during traversal + */ + public Object predecessor() { + return predecessor(0); + } + + + /** + * @param level nesting level, i.e., 0 returns the direct predecessor + * @return container of current entitity, i.e., predecessor during traversal + */ + public Object predecessor( int level ) { + int size = stack.size(); + if ((size < 2) || (level < 0)) { + return null; + } else { + return stack.elementAt(size - (level + 2)); // size - 1 == current + } + } + + + /** @return current object + */ + public Object current() { + return stack.peek(); + } + + + /** + * @param clazz Class to traverse + * @param visitor visitor object to apply to all components + */ + public DescendingVisitor(JavaClass clazz, Visitor visitor) { + this.clazz = clazz; + this.visitor = visitor; + } + + + /** + * Start traversal. + */ + public void visit() { + clazz.accept(this); + } + + + public void visitJavaClass( JavaClass _clazz ) { + stack.push(_clazz); + _clazz.accept(visitor); + Field[] fields = _clazz.getFields(); + for (int i = 0; i < fields.length; i++) { + fields[i].accept(this); + } + Method[] methods = _clazz.getMethods(); + for (int i = 0; i < methods.length; i++) { + methods[i].accept(this); + } + Attribute[] attributes = _clazz.getAttributes(); + for (int i = 0; i < attributes.length; i++) { + attributes[i].accept(this); + } + _clazz.getConstantPool().accept(this); + stack.pop(); + } + + + public void visitField( Field field ) { + stack.push(field); + field.accept(visitor); + Attribute[] attributes = field.getAttributes(); + for (int i = 0; i < attributes.length; i++) { + attributes[i].accept(this); + } + stack.pop(); + } + + + public void visitConstantValue( ConstantValue cv ) { + stack.push(cv); + cv.accept(visitor); + stack.pop(); + } + + + public void visitMethod( Method method ) { + stack.push(method); + method.accept(visitor); + Attribute[] attributes = method.getAttributes(); + for (int i = 0; i < attributes.length; i++) { + attributes[i].accept(this); + } + stack.pop(); + } + + + public void visitExceptionTable( ExceptionTable table ) { + stack.push(table); + table.accept(visitor); + stack.pop(); + } + + + public void visitCode( Code code ) { + stack.push(code); + code.accept(visitor); + CodeException[] table = code.getExceptionTable(); + for (int i = 0; i < table.length; i++) { + table[i].accept(this); + } + Attribute[] attributes = code.getAttributes(); + for (int i = 0; i < attributes.length; i++) { + attributes[i].accept(this); + } + stack.pop(); + } + + + public void visitCodeException( CodeException ce ) { + stack.push(ce); + ce.accept(visitor); + stack.pop(); + } + + + public void visitLineNumberTable( LineNumberTable table ) { + stack.push(table); + table.accept(visitor); + LineNumber[] numbers = table.getLineNumberTable(); + for (int i = 0; i < numbers.length; i++) { + numbers[i].accept(this); + } + stack.pop(); + } + + + public void visitLineNumber( LineNumber number ) { + stack.push(number); + number.accept(visitor); + stack.pop(); + } + + + public void visitLocalVariableTable( LocalVariableTable table ) { + stack.push(table); + table.accept(visitor); + LocalVariable[] vars = table.getLocalVariableTable(); + for (int i = 0; i < vars.length; i++) { + vars[i].accept(this); + } + stack.pop(); + } + + + public void visitStackMap( StackMap table ) { + stack.push(table); + table.accept(visitor); + StackMapEntry[] vars = table.getStackMap(); + for (int i = 0; i < vars.length; i++) { + vars[i].accept(this); + } + stack.pop(); + } + + + public void visitStackMapEntry( StackMapEntry var ) { + stack.push(var); + var.accept(visitor); + stack.pop(); + } + + + public void visitLocalVariable( LocalVariable var ) { + stack.push(var); + var.accept(visitor); + stack.pop(); + } + + + public void visitConstantPool( ConstantPool cp ) { + stack.push(cp); + cp.accept(visitor); + Constant[] constants = cp.getConstantPool(); + for (int i = 1; i < constants.length; i++) { + if (constants[i] != null) { + constants[i].accept(this); + } + } + stack.pop(); + } + + + public void visitConstantClass( ConstantClass constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitConstantDouble( ConstantDouble constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitConstantFieldref( ConstantFieldref constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitConstantFloat( ConstantFloat constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitConstantInteger( ConstantInteger constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitConstantInterfaceMethodref( ConstantInterfaceMethodref constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitConstantLong( ConstantLong constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitConstantMethodref( ConstantMethodref constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitConstantNameAndType( ConstantNameAndType constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitConstantString( ConstantString constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitConstantUtf8( ConstantUtf8 constant ) { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + + public void visitInnerClasses( InnerClasses ic ) { + stack.push(ic); + ic.accept(visitor); + InnerClass[] ics = ic.getInnerClasses(); + for (int i = 0; i < ics.length; i++) { + ics[i].accept(this); + } + stack.pop(); + } + + + public void visitInnerClass( InnerClass inner ) { + stack.push(inner); + inner.accept(visitor); + stack.pop(); + } + + + public void visitDeprecated( Deprecated attribute ) { + stack.push(attribute); + attribute.accept(visitor); + stack.pop(); + } + + + public void visitSignature( Signature attribute ) { + stack.push(attribute); + attribute.accept(visitor); + stack.pop(); + } + + + public void visitSourceFile( SourceFile attribute ) { + stack.push(attribute); + attribute.accept(visitor); + stack.pop(); + } + + + public void visitSynthetic( Synthetic attribute ) { + stack.push(attribute); + attribute.accept(visitor); + stack.pop(); + } + + + public void visitUnknown( Unknown attribute ) { + stack.push(attribute); + attribute.accept(visitor); + stack.pop(); + } +} diff --git a/src/org/apache/bcel/classfile/EmptyVisitor.java b/src/org/apache/bcel/classfile/EmptyVisitor.java new file mode 100644 index 0000000..8652507 --- /dev/null +++ b/src/org/apache/bcel/classfile/EmptyVisitor.java @@ -0,0 +1,161 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +/** + * Visitor with empty method bodies, can be extended and used in conjunction with the + * DescendingVisitor class, e.g. + * + * By courtesy of David Spencer. + * + * @see DescendingVisitor + * @version $Id: EmptyVisitor.java 388707 2006-03-25 05:40:28Z tcurdt $ + * + */ +public class EmptyVisitor implements Visitor { + + protected EmptyVisitor() { + } + + + public void visitCode( Code obj ) { + } + + + public void visitCodeException( CodeException obj ) { + } + + + public void visitConstantClass( ConstantClass obj ) { + } + + + public void visitConstantDouble( ConstantDouble obj ) { + } + + + public void visitConstantFieldref( ConstantFieldref obj ) { + } + + + public void visitConstantFloat( ConstantFloat obj ) { + } + + + public void visitConstantInteger( ConstantInteger obj ) { + } + + + public void visitConstantInterfaceMethodref( ConstantInterfaceMethodref obj ) { + } + + + public void visitConstantLong( ConstantLong obj ) { + } + + + public void visitConstantMethodref( ConstantMethodref obj ) { + } + + + public void visitConstantNameAndType( ConstantNameAndType obj ) { + } + + + public void visitConstantPool( ConstantPool obj ) { + } + + + public void visitConstantString( ConstantString obj ) { + } + + + public void visitConstantUtf8( ConstantUtf8 obj ) { + } + + + public void visitConstantValue( ConstantValue obj ) { + } + + + public void visitDeprecated( Deprecated obj ) { + } + + + public void visitExceptionTable( ExceptionTable obj ) { + } + + + public void visitField( Field obj ) { + } + + + public void visitInnerClass( InnerClass obj ) { + } + + + public void visitInnerClasses( InnerClasses obj ) { + } + + + public void visitJavaClass( JavaClass obj ) { + } + + + public void visitLineNumber( LineNumber obj ) { + } + + + public void visitLineNumberTable( LineNumberTable obj ) { + } + + + public void visitLocalVariable( LocalVariable obj ) { + } + + + public void visitLocalVariableTable( LocalVariableTable obj ) { + } + + + public void visitMethod( Method obj ) { + } + + + public void visitSignature( Signature obj ) { + } + + + public void visitSourceFile( SourceFile obj ) { + } + + + public void visitSynthetic( Synthetic obj ) { + } + + + public void visitUnknown( Unknown obj ) { + } + + + public void visitStackMap( StackMap obj ) { + } + + + public void visitStackMapEntry( StackMapEntry obj ) { + } +} diff --git a/src/org/apache/bcel/classfile/ExceptionTable.java b/src/org/apache/bcel/classfile/ExceptionTable.java new file mode 100644 index 0000000..b68bdc8 --- /dev/null +++ b/src/org/apache/bcel/classfile/ExceptionTable.java @@ -0,0 +1,180 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class represents the table of exceptions that are thrown by a + * method. This attribute may be used once per method. The name of + * this class is ExceptionTable for historical reasons; The + * Java Virtual Machine Specification, Second Edition defines this + * attribute using the name Exceptions (which is inconsistent + * with the other classes). + * + * @version $Id: ExceptionTable.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Code + */ +public final class ExceptionTable extends Attribute { + + private int number_of_exceptions; // Table of indices into + private int[] exception_index_table; // constant pool + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use copy() for a physical copy. + */ + public ExceptionTable(ExceptionTable c) { + this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool()); + } + + + /** + * @param name_index Index in constant pool + * @param length Content length in bytes + * @param exception_index_table Table of indices in constant pool + * @param constant_pool Array of constants + */ + public ExceptionTable(int name_index, int length, int[] exception_index_table, + ConstantPool constant_pool) { + super(Constants.ATTR_EXCEPTIONS, name_index, length, constant_pool); + setExceptionIndexTable(exception_index_table); + } + + + /** + * Construct object from file stream. + * @param name_index Index in constant pool + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + ExceptionTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, (int[]) null, constant_pool); + number_of_exceptions = file.readUnsignedShort(); + exception_index_table = new int[number_of_exceptions]; + for (int i = 0; i < number_of_exceptions; i++) { + exception_index_table[i] = file.readUnsignedShort(); + } + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionTable(this); + } + + + /** + * Dump exceptions attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + file.writeShort(number_of_exceptions); + for (int i = 0; i < number_of_exceptions; i++) { + file.writeShort(exception_index_table[i]); + } + } + + + /** + * @return Array of indices into constant pool of thrown exceptions. + */ + public final int[] getExceptionIndexTable() { + return exception_index_table; + } + + + /** + * @return Length of exception table. + */ + public final int getNumberOfExceptions() { + return number_of_exceptions; + } + + + /** + * @return class names of thrown exceptions + */ + public final String[] getExceptionNames() { + String[] names = new String[number_of_exceptions]; + for (int i = 0; i < number_of_exceptions; i++) { + names[i] = constant_pool.getConstantString(exception_index_table[i], + Constants.CONSTANT_Class).replace('/', '.'); + } + return names; + } + + + /** + * @param exception_index_table the list of exception indexes + * Also redefines number_of_exceptions according to table length. + */ + public final void setExceptionIndexTable( int[] exception_index_table ) { + this.exception_index_table = exception_index_table; + number_of_exceptions = (exception_index_table == null) ? 0 : exception_index_table.length; + } + + + /** + * @return String representation, i.e., a list of thrown exceptions. + */ + public final String toString() { + StringBuffer buf = new StringBuffer(""); + String str; + for (int i = 0; i < number_of_exceptions; i++) { + str = constant_pool.getConstantString(exception_index_table[i], + Constants.CONSTANT_Class); + buf.append(Utility.compactClassName(str, false)); + if (i < number_of_exceptions - 1) { + buf.append(", "); + } + } + return buf.toString(); + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + ExceptionTable c = (ExceptionTable) clone(); + if (exception_index_table != null) { + c.exception_index_table = new int[exception_index_table.length]; + System.arraycopy(exception_index_table, 0, c.exception_index_table, 0, + exception_index_table.length); + } + c.constant_pool = _constant_pool; + return c; + } +} diff --git a/src/org/apache/bcel/classfile/Field.java b/src/org/apache/bcel/classfile/Field.java new file mode 100644 index 0000000..7cbffdd --- /dev/null +++ b/src/org/apache/bcel/classfile/Field.java @@ -0,0 +1,190 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.IOException; +import org.apache.bcel.Constants; +import org.apache.bcel.generic.Type; +import org.apache.bcel.util.BCELComparator; + +/** + * This class represents the field info structure, i.e., the representation + * for a variable in the class. See JVM specification for details. + * + * @version $Id: Field.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class Field extends FieldOrMethod { + + private static BCELComparator _cmp = new BCELComparator() { + + public boolean equals( Object o1, Object o2 ) { + Field THIS = (Field) o1; + Field THAT = (Field) o2; + return THIS.getName().equals(THAT.getName()) + && THIS.getSignature().equals(THAT.getSignature()); + } + + + public int hashCode( Object o ) { + Field THIS = (Field) o; + return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + } + }; + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + public Field(Field c) { + super(c); + } + + + /** + * Construct object from file stream. + * @param file Input stream + */ + Field(DataInputStream file, ConstantPool constant_pool) throws IOException, + ClassFormatException { + super(file, constant_pool); + } + + + /** + * @param access_flags Access rights of field + * @param name_index Points to field name in constant pool + * @param signature_index Points to encoded signature + * @param attributes Collection of attributes + * @param constant_pool Array of constants + */ + public Field(int access_flags, int name_index, int signature_index, Attribute[] attributes, + ConstantPool constant_pool) { + super(access_flags, name_index, signature_index, attributes, constant_pool); + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitField(this); + } + + + /** + * @return constant value associated with this field (may be null) + */ + public final ConstantValue getConstantValue() { + for (int i = 0; i < attributes_count; i++) { + if (attributes[i].getTag() == Constants.ATTR_CONSTANT_VALUE) { + return (ConstantValue) attributes[i]; + } + } + return null; + } + + + /** + * Return string representation close to declaration format, + * `public static final short MAX = 100', e.g.. + * + * @return String representation of field, including the signature. + */ + public final String toString() { + String name, signature, access; // Short cuts to constant pool + // Get names from constant pool + access = Utility.accessToString(access_flags); + access = access.equals("") ? "" : (access + " "); + signature = Utility.signatureToString(getSignature()); + name = getName(); + StringBuffer buf = new StringBuffer(64); + buf.append(access).append(signature).append(" ").append(name); + ConstantValue cv = getConstantValue(); + if (cv != null) { + buf.append(" = ").append(cv); + } + for (int i = 0; i < attributes_count; i++) { + Attribute a = attributes[i]; + if (!(a instanceof ConstantValue)) { + buf.append(" [").append(a.toString()).append("]"); + } + } + return buf.toString(); + } + + + /** + * @return deep copy of this field + */ + public final Field copy( ConstantPool _constant_pool ) { + return (Field) copy_(_constant_pool); + } + + + /** + * @return type of field + */ + public Type getType() { + return Type.getReturnType(getSignature()); + } + + + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return _cmp; + } + + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator( BCELComparator comparator ) { + _cmp = comparator; + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default two Field objects are said to be equal when + * their names and signatures are equal. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals( Object obj ) { + return _cmp.equals(this, obj); + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default return the hashcode of the field's name XOR signature. + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return _cmp.hashCode(this); + } +} diff --git a/src/org/apache/bcel/classfile/FieldOrMethod.java b/src/org/apache/bcel/classfile/FieldOrMethod.java new file mode 100644 index 0000000..885164b --- /dev/null +++ b/src/org/apache/bcel/classfile/FieldOrMethod.java @@ -0,0 +1,206 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * Abstract super class for fields and methods. + * + * @version $Id: FieldOrMethod.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node { + + protected int name_index; // Points to field name in constant pool + protected int signature_index; // Points to encoded signature + protected int attributes_count; // No. of attributes + protected Attribute[] attributes; // Collection of attributes + protected ConstantPool constant_pool; + + + FieldOrMethod() { + } + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + protected FieldOrMethod(FieldOrMethod c) { + this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c + .getConstantPool()); + } + + + /** + * Construct object from file stream. + * @param file Input stream + * @throws IOException + * @throws ClassFormatException + */ + protected FieldOrMethod(DataInputStream file, ConstantPool constant_pool) throws IOException, + ClassFormatException { + this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, + constant_pool); + attributes_count = file.readUnsignedShort(); + attributes = new Attribute[attributes_count]; + for (int i = 0; i < attributes_count; i++) { + attributes[i] = Attribute.readAttribute(file, constant_pool); + } + } + + + /** + * @param access_flags Access rights of method + * @param name_index Points to field name in constant pool + * @param signature_index Points to encoded signature + * @param attributes Collection of attributes + * @param constant_pool Array of constants + */ + protected FieldOrMethod(int access_flags, int name_index, int signature_index, + Attribute[] attributes, ConstantPool constant_pool) { + this.access_flags = access_flags; + this.name_index = name_index; + this.signature_index = signature_index; + this.constant_pool = constant_pool; + setAttributes(attributes); + } + + + /** + * Dump object to file stream on binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeShort(access_flags); + file.writeShort(name_index); + file.writeShort(signature_index); + file.writeShort(attributes_count); + for (int i = 0; i < attributes_count; i++) { + attributes[i].dump(file); + } + } + + + /** + * @return Collection of object attributes. + */ + public final Attribute[] getAttributes() { + return attributes; + } + + + /** + * @param attributes Collection of object attributes. + */ + public final void setAttributes( Attribute[] attributes ) { + this.attributes = attributes; + attributes_count = (attributes == null) ? 0 : attributes.length; + } + + + /** + * @return Constant pool used by this object. + */ + public final ConstantPool getConstantPool() { + return constant_pool; + } + + + /** + * @param constant_pool Constant pool to be used for this object. + */ + public final void setConstantPool( ConstantPool constant_pool ) { + this.constant_pool = constant_pool; + } + + + /** + * @return Index in constant pool of object's name. + */ + public final int getNameIndex() { + return name_index; + } + + + /** + * @param name_index Index in constant pool of object's name. + */ + public final void setNameIndex( int name_index ) { + this.name_index = name_index; + } + + + /** + * @return Index in constant pool of field signature. + */ + public final int getSignatureIndex() { + return signature_index; + } + + + /** + * @param signature_index Index in constant pool of field signature. + */ + public final void setSignatureIndex( int signature_index ) { + this.signature_index = signature_index; + } + + + /** + * @return Name of object, i.e., method name or field name + */ + public final String getName() { + ConstantUtf8 c; + c = (ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + + /** + * @return String representation of object's type signature (java style) + */ + public final String getSignature() { + ConstantUtf8 c; + c = (ConstantUtf8) constant_pool.getConstant(signature_index, Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + + /** + * @return deep copy of this field + */ + protected FieldOrMethod copy_( ConstantPool _constant_pool ) { + try { + FieldOrMethod c = (FieldOrMethod) clone(); + c.constant_pool = _constant_pool; + c.attributes = new Attribute[attributes_count]; + for (int i = 0; i < attributes_count; i++) { + c.attributes[i] = attributes[i].copy(_constant_pool); + } + return c; + } catch (CloneNotSupportedException e) { + return null; + } + } +} diff --git a/src/org/apache/bcel/classfile/InnerClass.java b/src/org/apache/bcel/classfile/InnerClass.java new file mode 100644 index 0000000..794ade5 --- /dev/null +++ b/src/org/apache/bcel/classfile/InnerClass.java @@ -0,0 +1,214 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.Serializable; +import org.apache.bcel.Constants; + +/** + * This class represents a inner class attribute, i.e., the class + * indices of the inner and outer classes, the name and the attributes + * of the inner class. + * + * @version $Id: InnerClass.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see InnerClasses + */ +public final class InnerClass implements Cloneable, Node, Serializable { + + private int inner_class_index; + private int outer_class_index; + private int inner_name_index; + private int inner_access_flags; + + + /** + * Initialize from another object. + */ + public InnerClass(InnerClass c) { + this(c.getInnerClassIndex(), c.getOuterClassIndex(), c.getInnerNameIndex(), c + .getInnerAccessFlags()); + } + + + /** + * Construct object from file stream. + * @param file Input stream + * @throws IOException + */ + InnerClass(DataInputStream file) throws IOException { + this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file + .readUnsignedShort()); + } + + + /** + * @param inner_class_index Class index in constant pool of inner class + * @param outer_class_index Class index in constant pool of outer class + * @param inner_name_index Name index in constant pool of inner class + * @param inner_access_flags Access flags of inner class + */ + public InnerClass(int inner_class_index, int outer_class_index, int inner_name_index, + int inner_access_flags) { + this.inner_class_index = inner_class_index; + this.outer_class_index = outer_class_index; + this.inner_name_index = inner_name_index; + this.inner_access_flags = inner_access_flags; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitInnerClass(this); + } + + + /** + * Dump inner class attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeShort(inner_class_index); + file.writeShort(outer_class_index); + file.writeShort(inner_name_index); + file.writeShort(inner_access_flags); + } + + + /** + * @return access flags of inner class. + */ + public final int getInnerAccessFlags() { + return inner_access_flags; + } + + + /** + * @return class index of inner class. + */ + public final int getInnerClassIndex() { + return inner_class_index; + } + + + /** + * @return name index of inner class. + */ + public final int getInnerNameIndex() { + return inner_name_index; + } + + + /** + * @return class index of outer class. + */ + public final int getOuterClassIndex() { + return outer_class_index; + } + + + /** + * @param inner_access_flags access flags for this inner class + */ + public final void setInnerAccessFlags( int inner_access_flags ) { + this.inner_access_flags = inner_access_flags; + } + + + /** + * @param inner_class_index index into the constant pool for this class + */ + public final void setInnerClassIndex( int inner_class_index ) { + this.inner_class_index = inner_class_index; + } + + + /** + * @param inner_name_index index into the constant pool for this class's name + */ + public final void setInnerNameIndex( int inner_name_index ) { + this.inner_name_index = inner_name_index; + } + + + /** + * @param outer_class_index index into the constant pool for the owning class + */ + public final void setOuterClassIndex( int outer_class_index ) { + this.outer_class_index = outer_class_index; + } + + + /** + * @return String representation. + */ + public final String toString() { + return "InnerClass(" + inner_class_index + ", " + outer_class_index + ", " + + inner_name_index + ", " + inner_access_flags + ")"; + } + + + /** + * @return Resolved string representation + */ + public final String toString( ConstantPool constant_pool ) { + String inner_class_name, outer_class_name, inner_name, access; + inner_class_name = constant_pool.getConstantString(inner_class_index, + Constants.CONSTANT_Class); + inner_class_name = Utility.compactClassName(inner_class_name); + if (outer_class_index != 0) { + outer_class_name = constant_pool.getConstantString(outer_class_index, + Constants.CONSTANT_Class); + outer_class_name = Utility.compactClassName(outer_class_name); + } else { + outer_class_name = ""; + } + if (inner_name_index != 0) { + inner_name = ((ConstantUtf8) constant_pool.getConstant(inner_name_index, + Constants.CONSTANT_Utf8)).getBytes(); + } else { + inner_name = ""; + } + access = Utility.accessToString(inner_access_flags, true); + access = access.equals("") ? "" : (access + " "); + return "InnerClass:" + access + inner_class_name + "(\"" + outer_class_name + "\", \"" + + inner_name + "\")"; + } + + + /** + * @return deep copy of this object + */ + public InnerClass copy() { + try { + return (InnerClass) clone(); + } catch (CloneNotSupportedException e) { + } + return null; + } +} diff --git a/src/org/apache/bcel/classfile/InnerClasses.java b/src/org/apache/bcel/classfile/InnerClasses.java new file mode 100644 index 0000000..dd63e9b --- /dev/null +++ b/src/org/apache/bcel/classfile/InnerClasses.java @@ -0,0 +1,150 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from Attribute and denotes that this class + * is an Inner class of another. + * to the source file of this class. + * It is instantiated from the Attribute.readAttribute() method. + * + * @version $Id: InnerClasses.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Attribute + */ +public final class InnerClasses extends Attribute { + + private InnerClass[] inner_classes; + private int number_of_classes; + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + public InnerClasses(InnerClasses c) { + this(c.getNameIndex(), c.getLength(), c.getInnerClasses(), c.getConstantPool()); + } + + + /** + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param inner_classes array of inner classes attributes + * @param constant_pool Array of constants + */ + public InnerClasses(int name_index, int length, InnerClass[] inner_classes, + ConstantPool constant_pool) { + super(Constants.ATTR_INNER_CLASSES, name_index, length, constant_pool); + setInnerClasses(inner_classes); + } + + + /** + * Construct object from file stream. + * + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + InnerClasses(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, (InnerClass[]) null, constant_pool); + number_of_classes = file.readUnsignedShort(); + inner_classes = new InnerClass[number_of_classes]; + for (int i = 0; i < number_of_classes; i++) { + inner_classes[i] = new InnerClass(file); + } + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitInnerClasses(this); + } + + + /** + * Dump source file attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + file.writeShort(number_of_classes); + for (int i = 0; i < number_of_classes; i++) { + inner_classes[i].dump(file); + } + } + + + /** + * @return array of inner class "records" + */ + public final InnerClass[] getInnerClasses() { + return inner_classes; + } + + + /** + * @param inner_classes the array of inner classes + */ + public final void setInnerClasses( InnerClass[] inner_classes ) { + this.inner_classes = inner_classes; + number_of_classes = (inner_classes == null) ? 0 : inner_classes.length; + } + + + /** + * @return String representation. + */ + public final String toString() { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < number_of_classes; i++) { + buf.append(inner_classes[i].toString(constant_pool)).append("\n"); + } + return buf.toString(); + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + InnerClasses c = (InnerClasses) clone(); + c.inner_classes = new InnerClass[number_of_classes]; + for (int i = 0; i < number_of_classes; i++) { + c.inner_classes[i] = inner_classes[i].copy(); + } + c.constant_pool = _constant_pool; + return c; + } +} diff --git a/src/org/apache/bcel/classfile/JavaClass.java b/src/org/apache/bcel/classfile/JavaClass.java new file mode 100644 index 0000000..b2985cb --- /dev/null +++ b/src/org/apache/bcel/classfile/JavaClass.java @@ -0,0 +1,866 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; +import org.apache.bcel.Constants; +import org.apache.bcel.generic.Type; +import org.apache.bcel.util.BCELComparator; +import org.apache.bcel.util.ClassQueue; +import org.apache.bcel.util.SyntheticRepository; + +/** + * Represents a Java class, i.e., the data structures, constant pool, + * fields, methods and commands contained in a Java .class file. + * See JVM specification for details. + * The intent of this class is to represent a parsed or otherwise existing + * class file. Those interested in programatically generating classes + * should see the ClassGen class. + + * @version $Id: JavaClass.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @see org.apache.bcel.generic.ClassGen + * @author M. Dahm + */ +public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable { + + private String file_name; + private String package_name; + private String source_file_name = ""; + private int class_name_index; + private int superclass_name_index; + private String class_name; + private String superclass_name; + private int major, minor; // Compiler version + private ConstantPool constant_pool; // Constant pool + private int[] interfaces; // implemented interfaces + private String[] interface_names; + private Field[] fields; // Fields, i.e., variables of class + private Method[] methods; // methods defined in the class + private Attribute[] attributes; // attributes defined in the class + private byte source = HEAP; // Generated in memory + public static final byte HEAP = 1; + public static final byte FILE = 2; + public static final byte ZIP = 3; + static boolean debug = false; // Debugging on/off + static char sep = '/'; // directory separator + private static BCELComparator _cmp = new BCELComparator() { + + public boolean equals( Object o1, Object o2 ) { + JavaClass THIS = (JavaClass) o1; + JavaClass THAT = (JavaClass) o2; + return THIS.getClassName().equals(THAT.getClassName()); + } + + + public int hashCode( Object o ) { + JavaClass THIS = (JavaClass) o; + return THIS.getClassName().hashCode(); + } + }; + /** + * In cases where we go ahead and create something, + * use the default SyntheticRepository, because we + * don't know any better. + */ + private transient org.apache.bcel.util.Repository repository = SyntheticRepository + .getInstance(); + + + /** + * Constructor gets all contents as arguments. + * + * @param class_name_index Index into constant pool referencing a + * ConstantClass that represents this class. + * @param superclass_name_index Index into constant pool referencing a + * ConstantClass that represents this class's superclass. + * @param file_name File name + * @param major Major compiler version + * @param minor Minor compiler version + * @param access_flags Access rights defined by bit flags + * @param constant_pool Array of constants + * @param interfaces Implemented interfaces + * @param fields Class fields + * @param methods Class methods + * @param attributes Class attributes + * @param source Read from file or generated in memory? + */ + public JavaClass(int class_name_index, int superclass_name_index, String file_name, int major, + int minor, int access_flags, ConstantPool constant_pool, int[] interfaces, + Field[] fields, Method[] methods, Attribute[] attributes, byte source) { + if (interfaces == null) { + interfaces = new int[0]; + } + if (attributes == null) { + attributes = new Attribute[0]; + } + if (fields == null) { + fields = new Field[0]; + } + if (methods == null) { + methods = new Method[0]; + } + this.class_name_index = class_name_index; + this.superclass_name_index = superclass_name_index; + this.file_name = file_name; + this.major = major; + this.minor = minor; + this.access_flags = access_flags; + this.constant_pool = constant_pool; + this.interfaces = interfaces; + this.fields = fields; + this.methods = methods; + this.attributes = attributes; + this.source = source; + // Get source file name if available + for (int i = 0; i < attributes.length; i++) { + if (attributes[i] instanceof SourceFile) { + source_file_name = ((SourceFile) attributes[i]).getSourceFileName(); + break; + } + } + /* According to the specification the following entries must be of type + * `ConstantClass' but we check that anyway via the + * `ConstPool.getConstant' method. + */ + class_name = constant_pool.getConstantString(class_name_index, Constants.CONSTANT_Class); + class_name = Utility.compactClassName(class_name, false); + int index = class_name.lastIndexOf('.'); + if (index < 0) { + package_name = ""; + } else { + package_name = class_name.substring(0, index); + } + if (superclass_name_index > 0) { + // May be zero -> class is java.lang.Object + superclass_name = constant_pool.getConstantString(superclass_name_index, + Constants.CONSTANT_Class); + superclass_name = Utility.compactClassName(superclass_name, false); + } else { + superclass_name = "java.lang.Object"; + } + interface_names = new String[interfaces.length]; + for (int i = 0; i < interfaces.length; i++) { + String str = constant_pool.getConstantString(interfaces[i], Constants.CONSTANT_Class); + interface_names[i] = Utility.compactClassName(str, false); + } + } + + + /** + * Constructor gets all contents as arguments. + * + * @param class_name_index Class name + * @param superclass_name_index Superclass name + * @param file_name File name + * @param major Major compiler version + * @param minor Minor compiler version + * @param access_flags Access rights defined by bit flags + * @param constant_pool Array of constants + * @param interfaces Implemented interfaces + * @param fields Class fields + * @param methods Class methods + * @param attributes Class attributes + */ + public JavaClass(int class_name_index, int superclass_name_index, String file_name, int major, + int minor, int access_flags, ConstantPool constant_pool, int[] interfaces, + Field[] fields, Method[] methods, Attribute[] attributes) { + this(class_name_index, superclass_name_index, file_name, major, minor, access_flags, + constant_pool, interfaces, fields, methods, attributes, HEAP); + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitJavaClass(this); + } + + + /* Print debug information depending on `JavaClass.debug' + */ + static final void Debug( String str ) { + if (debug) { + System.out.println(str); + } + } + + + /** + * Dump class to a file. + * + * @param file Output file + * @throws IOException + */ + public void dump( File file ) throws IOException { + String parent = file.getParent(); + if (parent != null) { + File dir = new File(parent); + dir.mkdirs(); + } + DataOutputStream dos = null; + try { + dos = new DataOutputStream(new FileOutputStream(file)); + dump(dos); + } finally { + if (dos != null) { + dos.close(); + } + } + } + + + /** + * Dump class to a file named file_name. + * + * @param _file_name Output file name + * @exception IOException + */ + public void dump( String _file_name ) throws IOException { + dump(new File(_file_name)); + } + + + /** + * @return class in binary format + */ + public byte[] getBytes() { + ByteArrayOutputStream s = new ByteArrayOutputStream(); + DataOutputStream ds = new DataOutputStream(s); + try { + dump(ds); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + ds.close(); + } catch (IOException e2) { + e2.printStackTrace(); + } + } + return s.toByteArray(); + } + + + /** + * Dump Java class to output stream in binary format. + * + * @param file Output stream + * @exception IOException + */ + public void dump( OutputStream file ) throws IOException { + dump(new DataOutputStream(file)); + } + + + /** + * Dump Java class to output stream in binary format. + * + * @param file Output stream + * @exception IOException + */ + public void dump( DataOutputStream file ) throws IOException { + file.writeInt(0xcafebabe); + file.writeShort(minor); + file.writeShort(major); + constant_pool.dump(file); + file.writeShort(access_flags); + file.writeShort(class_name_index); + file.writeShort(superclass_name_index); + file.writeShort(interfaces.length); + for (int i = 0; i < interfaces.length; i++) { + file.writeShort(interfaces[i]); + } + file.writeShort(fields.length); + for (int i = 0; i < fields.length; i++) { + fields[i].dump(file); + } + file.writeShort(methods.length); + for (int i = 0; i < methods.length; i++) { + methods[i].dump(file); + } + if (attributes != null) { + file.writeShort(attributes.length); + for (int i = 0; i < attributes.length; i++) { + attributes[i].dump(file); + } + } else { + file.writeShort(0); + } + file.flush(); + } + + + /** + * @return Attributes of the class. + */ + public Attribute[] getAttributes() { + return attributes; + } + + + /** + * @return Class name. + */ + public String getClassName() { + return class_name; + } + + + /** + * @return Package name. + */ + public String getPackageName() { + return package_name; + } + + + /** + * @return Class name index. + */ + public int getClassNameIndex() { + return class_name_index; + } + + + /** + * @return Constant pool. + */ + public ConstantPool getConstantPool() { + return constant_pool; + } + + + /** + * @return Fields, i.e., variables of the class. Like the JVM spec + * mandates for the classfile format, these fields are those specific to + * this class, and not those of the superclass or superinterfaces. + */ + public Field[] getFields() { + return fields; + } + + + /** + * @return File name of class, aka SourceFile attribute value + */ + public String getFileName() { + return file_name; + } + + + /** + * @return Names of implemented interfaces. + */ + public String[] getInterfaceNames() { + return interface_names; + } + + + /** + * @return Indices in constant pool of implemented interfaces. + */ + public int[] getInterfaceIndices() { + return interfaces; + } + + + /** + * @return Major number of class file version. + */ + public int getMajor() { + return major; + } + + + /** + * @return Methods of the class. + */ + public Method[] getMethods() { + return methods; + } + + + /** + * @return A org.apache.bcel.classfile.Method corresponding to + * java.lang.reflect.Method if any + */ + public Method getMethod( java.lang.reflect.Method m ) { + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + if (m.getName().equals(method.getName()) && (m.getModifiers() == method.getModifiers()) + && Type.getSignature(m).equals(method.getSignature())) { + return method; + } + } + return null; + } + + + /** + * @return Minor number of class file version. + */ + public int getMinor() { + return minor; + } + + + /** + * @return sbsolute path to file where this class was read from + */ + public String getSourceFileName() { + return source_file_name; + } + + + /** + * @return Superclass name. + */ + public String getSuperclassName() { + return superclass_name; + } + + + /** + * @return Class name index. + */ + public int getSuperclassNameIndex() { + return superclass_name_index; + } + + static { + // Debugging ... on/off + debug = Boolean.getBoolean("JavaClass.debug"); + // Get path separator either / or \ usually + String _sep = System.getProperty("file.separator"); + if (_sep != null) { + try { + JavaClass.sep = _sep.charAt(0); + } catch (StringIndexOutOfBoundsException e) { + } // Never reached + } + } + + + /** + * @param attributes . + */ + public void setAttributes( Attribute[] attributes ) { + this.attributes = attributes; + } + + + /** + * @param class_name . + */ + public void setClassName( String class_name ) { + this.class_name = class_name; + } + + + /** + * @param class_name_index . + */ + public void setClassNameIndex( int class_name_index ) { + this.class_name_index = class_name_index; + } + + + /** + * @param constant_pool . + */ + public void setConstantPool( ConstantPool constant_pool ) { + this.constant_pool = constant_pool; + } + + + /** + * @param fields . + */ + public void setFields( Field[] fields ) { + this.fields = fields; + } + + + /** + * Set File name of class, aka SourceFile attribute value + */ + public void setFileName( String file_name ) { + this.file_name = file_name; + } + + + /** + * @param interface_names . + */ + public void setInterfaceNames( String[] interface_names ) { + this.interface_names = interface_names; + } + + + /** + * @param interfaces . + */ + public void setInterfaces( int[] interfaces ) { + this.interfaces = interfaces; + } + + + /** + * @param major . + */ + public void setMajor( int major ) { + this.major = major; + } + + + /** + * @param methods . + */ + public void setMethods( Method[] methods ) { + this.methods = methods; + } + + + /** + * @param minor . + */ + public void setMinor( int minor ) { + this.minor = minor; + } + + + /** + * Set absolute path to file this class was read from. + */ + public void setSourceFileName( String source_file_name ) { + this.source_file_name = source_file_name; + } + + + /** + * @param superclass_name . + */ + public void setSuperclassName( String superclass_name ) { + this.superclass_name = superclass_name; + } + + + /** + * @param superclass_name_index . + */ + public void setSuperclassNameIndex( int superclass_name_index ) { + this.superclass_name_index = superclass_name_index; + } + + + /** + * @return String representing class contents. + */ + public String toString() { + String access = Utility.accessToString(access_flags, true); + access = access.equals("") ? "" : (access + " "); + StringBuffer buf = new StringBuffer(128); + buf.append(access).append(Utility.classOrInterface(access_flags)).append(" ").append( + class_name).append(" extends ").append( + Utility.compactClassName(superclass_name, false)).append('\n'); + int size = interfaces.length; + if (size > 0) { + buf.append("implements\t\t"); + for (int i = 0; i < size; i++) { + buf.append(interface_names[i]); + if (i < size - 1) { + buf.append(", "); + } + } + buf.append('\n'); + } + buf.append("filename\t\t").append(file_name).append('\n'); + buf.append("compiled from\t\t").append(source_file_name).append('\n'); + buf.append("compiler version\t").append(major).append(".").append(minor).append('\n'); + buf.append("access flags\t\t").append(access_flags).append('\n'); + buf.append("constant pool\t\t").append(constant_pool.getLength()).append(" entries\n"); + buf.append("ACC_SUPER flag\t\t").append(isSuper()).append("\n"); + if (attributes.length > 0) { + buf.append("\nAttribute(s):\n"); + for (int i = 0; i < attributes.length; i++) { + buf.append(indent(attributes[i])); + } + } + if (fields.length > 0) { + buf.append("\n").append(fields.length).append(" fields:\n"); + for (int i = 0; i < fields.length; i++) { + buf.append("\t").append(fields[i]).append('\n'); + } + } + if (methods.length > 0) { + buf.append("\n").append(methods.length).append(" methods:\n"); + for (int i = 0; i < methods.length; i++) { + buf.append("\t").append(methods[i]).append('\n'); + } + } + return buf.toString(); + } + + + private static final String indent( Object obj ) { + StringTokenizer tok = new StringTokenizer(obj.toString(), "\n"); + StringBuffer buf = new StringBuffer(); + while (tok.hasMoreTokens()) { + buf.append("\t").append(tok.nextToken()).append("\n"); + } + return buf.toString(); + } + + + /** + * @return deep copy of this class + */ + public JavaClass copy() { + JavaClass c = null; + try { + c = (JavaClass) clone(); + c.constant_pool = constant_pool.copy(); + c.interfaces = (int[]) interfaces.clone(); + c.interface_names = (String[]) interface_names.clone(); + c.fields = new Field[fields.length]; + for (int i = 0; i < fields.length; i++) { + c.fields[i] = fields[i].copy(c.constant_pool); + } + c.methods = new Method[methods.length]; + for (int i = 0; i < methods.length; i++) { + c.methods[i] = methods[i].copy(c.constant_pool); + } + c.attributes = new Attribute[attributes.length]; + for (int i = 0; i < attributes.length; i++) { + c.attributes[i] = attributes[i].copy(c.constant_pool); + } + } catch (CloneNotSupportedException e) { + } + return c; + } + + + public final boolean isSuper() { + return (access_flags & Constants.ACC_SUPER) != 0; + } + + + public final boolean isClass() { + return (access_flags & Constants.ACC_INTERFACE) == 0; + } + + + /** @return returns either HEAP (generated), FILE, or ZIP + */ + public final byte getSource() { + return source; + } + + + /********************* New repository functionality *********************/ + /** + * Gets the ClassRepository which holds its definition. By default + * this is the same as SyntheticRepository.getInstance(); + */ + public org.apache.bcel.util.Repository getRepository() { + return repository; + } + + + /** + * Sets the ClassRepository which loaded the JavaClass. + * Should be called immediately after parsing is done. + */ + public void setRepository( org.apache.bcel.util.Repository repository ) { + this.repository = repository; + } + + + /** Equivalent to runtime "instanceof" operator. + * + * @return true if this JavaClass is derived from the super class + * @throws ClassNotFoundException if superclasses or superinterfaces + * of this object can't be found + */ + public final boolean instanceOf( JavaClass super_class ) throws ClassNotFoundException { + if (this.equals(super_class)) { + return true; + } + JavaClass[] super_classes = getSuperClasses(); + for (int i = 0; i < super_classes.length; i++) { + if (super_classes[i].equals(super_class)) { + return true; + } + } + if (super_class.isInterface()) { + return implementationOf(super_class); + } + return false; + } + + + /** + * @return true, if this class is an implementation of interface inter + * @throws ClassNotFoundException if superclasses or superinterfaces + * of this class can't be found + */ + public boolean implementationOf( JavaClass inter ) throws ClassNotFoundException { + if (!inter.isInterface()) { + throw new IllegalArgumentException(inter.getClassName() + " is no interface"); + } + if (this.equals(inter)) { + return true; + } + JavaClass[] super_interfaces = getAllInterfaces(); + for (int i = 0; i < super_interfaces.length; i++) { + if (super_interfaces[i].equals(inter)) { + return true; + } + } + return false; + } + + + /** + * @return the superclass for this JavaClass object, or null if this + * is java.lang.Object + * @throws ClassNotFoundException if the superclass can't be found + */ + public JavaClass getSuperClass() throws ClassNotFoundException { + if ("java.lang.Object".equals(getClassName())) { + return null; + } + return repository.loadClass(getSuperclassName()); + } + + + /** + * @return list of super classes of this class in ascending order, i.e., + * java.lang.Object is always the last element + * @throws ClassNotFoundException if any of the superclasses can't be found + */ + public JavaClass[] getSuperClasses() throws ClassNotFoundException { + JavaClass clazz = this; + List allSuperClasses = new ArrayList(); + for (clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) { + allSuperClasses.add(clazz); + } + return (JavaClass[]) allSuperClasses.toArray(new JavaClass[allSuperClasses.size()]); + } + + + /** + * Get interfaces directly implemented by this JavaClass. + */ + public JavaClass[] getInterfaces() throws ClassNotFoundException { + String[] _interfaces = getInterfaceNames(); + JavaClass[] classes = new JavaClass[_interfaces.length]; + for (int i = 0; i < _interfaces.length; i++) { + classes[i] = repository.loadClass(_interfaces[i]); + } + return classes; + } + + + /** + * Get all interfaces implemented by this JavaClass (transitively). + */ + public JavaClass[] getAllInterfaces() throws ClassNotFoundException { + ClassQueue queue = new ClassQueue(); + Set allInterfaces = new TreeSet(); + queue.enqueue(this); + while (!queue.empty()) { + JavaClass clazz = queue.dequeue(); + JavaClass souper = clazz.getSuperClass(); + JavaClass[] _interfaces = clazz.getInterfaces(); + if (clazz.isInterface()) { + allInterfaces.add(clazz); + } else { + if (souper != null) { + queue.enqueue(souper); + } + } + for (int i = 0; i < _interfaces.length; i++) { + queue.enqueue(_interfaces[i]); + } + } + return (JavaClass[]) allInterfaces.toArray(new JavaClass[allInterfaces.size()]); + } + + + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return _cmp; + } + + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator( BCELComparator comparator ) { + _cmp = comparator; + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default two JavaClass objects are said to be equal when + * their class names are equal. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals( Object obj ) { + return _cmp.equals(this, obj); + } + + + /** + * Return the natural ordering of two JavaClasses. + * This ordering is based on the class name + */ + public int compareTo( Object obj ) { + return getClassName().compareTo(((JavaClass) obj).getClassName()); + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default return the hashcode of the class name. + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return _cmp.hashCode(this); + } +} diff --git a/src/org/apache/bcel/classfile/LineNumber.java b/src/org/apache/bcel/classfile/LineNumber.java new file mode 100644 index 0000000..954aa33 --- /dev/null +++ b/src/org/apache/bcel/classfile/LineNumber.java @@ -0,0 +1,141 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.Serializable; + +/** + * This class represents a (PC offset, line number) pair, i.e., a line number in + * the source that corresponds to a relative address in the byte code. This + * is used for debugging purposes. + * + * @version $Id: LineNumber.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see LineNumberTable + */ +public final class LineNumber implements Cloneable, Node, Serializable { + + private int start_pc; // Program Counter (PC) corresponds to line + private int line_number; // number in source file + + + /** + * Initialize from another object. + */ + public LineNumber(LineNumber c) { + this(c.getStartPC(), c.getLineNumber()); + } + + + /** + * Construct object from file stream. + * @param file Input stream + * @throws IOException + */ + LineNumber(DataInputStream file) throws IOException { + this(file.readUnsignedShort(), file.readUnsignedShort()); + } + + + /** + * @param start_pc Program Counter (PC) corresponds to + * @param line_number line number in source file + */ + public LineNumber(int start_pc, int line_number) { + this.start_pc = start_pc; + this.line_number = line_number; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitLineNumber(this); + } + + + /** + * Dump line number/pc pair to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeShort(start_pc); + file.writeShort(line_number); + } + + + /** + * @return Corresponding source line + */ + public final int getLineNumber() { + return line_number; + } + + + /** + * @return PC in code + */ + public final int getStartPC() { + return start_pc; + } + + + /** + * @param line_number the source line number + */ + public final void setLineNumber( int line_number ) { + this.line_number = line_number; + } + + + /** + * @param start_pc the pc for this line number + */ + public final void setStartPC( int start_pc ) { + this.start_pc = start_pc; + } + + + /** + * @return String representation + */ + public final String toString() { + return "LineNumber(" + start_pc + ", " + line_number + ")"; + } + + + /** + * @return deep copy of this object + */ + public LineNumber copy() { + try { + return (LineNumber) clone(); + } catch (CloneNotSupportedException e) { + } + return null; + } +} diff --git a/src/org/apache/bcel/classfile/LineNumberTable.java b/src/org/apache/bcel/classfile/LineNumberTable.java new file mode 100644 index 0000000..33e93ed --- /dev/null +++ b/src/org/apache/bcel/classfile/LineNumberTable.java @@ -0,0 +1,208 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class represents a table of line numbers for debugging + * purposes. This attribute is used by the Code attribute. It + * contains pairs of PCs and line numbers. + * + * @version $Id: LineNumberTable.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Code + * @see LineNumber + */ +public final class LineNumberTable extends Attribute { + + private int line_number_table_length; + private LineNumber[] line_number_table; // Table of line/numbers pairs + + + /* + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use copy() for a physical copy. + */ + public LineNumberTable(LineNumberTable c) { + this(c.getNameIndex(), c.getLength(), c.getLineNumberTable(), c.getConstantPool()); + } + + + /* + * @param name_index Index of name + * @param length Content length in bytes + * @param line_number_table Table of line/numbers pairs + * @param constant_pool Array of constants + */ + public LineNumberTable(int name_index, int length, LineNumber[] line_number_table, + ConstantPool constant_pool) { + super(Constants.ATTR_LINE_NUMBER_TABLE, name_index, length, constant_pool); + setLineNumberTable(line_number_table); + } + + + /** + * Construct object from file stream. + * @param name_index Index of name + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + LineNumberTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, (LineNumber[]) null, constant_pool); + line_number_table_length = (file.readUnsignedShort()); + line_number_table = new LineNumber[line_number_table_length]; + for (int i = 0; i < line_number_table_length; i++) { + line_number_table[i] = new LineNumber(file); + } + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitLineNumberTable(this); + } + + + /** + * Dump line number table attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + file.writeShort(line_number_table_length); + for (int i = 0; i < line_number_table_length; i++) { + line_number_table[i].dump(file); + } + } + + + /** + * @return Array of (pc offset, line number) pairs. + */ + public final LineNumber[] getLineNumberTable() { + return line_number_table; + } + + + /** + * @param line_number_table the line number entries for this table + */ + public final void setLineNumberTable( LineNumber[] line_number_table ) { + this.line_number_table = line_number_table; + line_number_table_length = (line_number_table == null) ? 0 : line_number_table.length; + } + + + /** + * @return String representation. + */ + public final String toString() { + StringBuffer buf = new StringBuffer(); + StringBuffer line = new StringBuffer(); + String newLine = System.getProperty("line.separator", "\n"); + for (int i = 0; i < line_number_table_length; i++) { + line.append(line_number_table[i].toString()); + if (i < line_number_table_length - 1) { + line.append(", "); + } + if (line.length() > 72) { + line.append(newLine); + buf.append(line.toString()); + line.setLength(0); + } + } + buf.append(line); + return buf.toString(); + } + + + /** + * Map byte code positions to source code lines. + * + * @param pos byte code offset + * @return corresponding line in source code + */ + public int getSourceLine( int pos ) { + int l = 0, r = line_number_table_length - 1; + if (r < 0) { + return -1; + } + int min_index = -1, min = -1; + /* Do a binary search since the array is ordered. + */ + do { + int i = (l + r) / 2; + int j = line_number_table[i].getStartPC(); + if (j == pos) { + return line_number_table[i].getLineNumber(); + } else if (pos < j) { + r = i - 1; + } else { + l = i + 1; + } + /* If exact match can't be found (which is the most common case) + * return the line number that corresponds to the greatest index less + * than pos. + */ + if (j < pos && j > min) { + min = j; + min_index = i; + } + } while (l <= r); + /* It's possible that we did not find any valid entry for the bytecode + * offset we were looking for. + */ + if (min_index < 0) { + return -1; + } + return line_number_table[min_index].getLineNumber(); + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + LineNumberTable c = (LineNumberTable) clone(); + c.line_number_table = new LineNumber[line_number_table_length]; + for (int i = 0; i < line_number_table_length; i++) { + c.line_number_table[i] = line_number_table[i].copy(); + } + c.constant_pool = _constant_pool; + return c; + } + + + public final int getTableLength() { + return line_number_table_length; + } +} diff --git a/src/org/apache/bcel/classfile/LocalVariable.java b/src/org/apache/bcel/classfile/LocalVariable.java new file mode 100644 index 0000000..8de890b --- /dev/null +++ b/src/org/apache/bcel/classfile/LocalVariable.java @@ -0,0 +1,248 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.Serializable; +import org.apache.bcel.Constants; + +/** + * This class represents a local variable within a method. It contains its + * scope, name, signature and index on the method's frame. + * + * @version $Id: LocalVariable.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see LocalVariableTable + */ +public final class LocalVariable implements Constants, Cloneable, Node, Serializable { + + private int start_pc; // Range in which the variable is valid + private int length; + private int name_index; // Index in constant pool of variable name + private int signature_index; // Index of variable signature + private int index; /* Variable is `index'th local variable on + * this method's frame. + */ + private ConstantPool constant_pool; + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use copy() for a physical copy. + */ + public LocalVariable(LocalVariable c) { + this(c.getStartPC(), c.getLength(), c.getNameIndex(), c.getSignatureIndex(), c.getIndex(), + c.getConstantPool()); + } + + + /** + * Construct object from file stream. + * @param file Input stream + * @throws IOException + */ + LocalVariable(DataInputStream file, ConstantPool constant_pool) throws IOException { + this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file + .readUnsignedShort(), file.readUnsignedShort(), constant_pool); + } + + + /** + * @param start_pc Range in which the variable + * @param length ... is valid + * @param name_index Index in constant pool of variable name + * @param signature_index Index of variable's signature + * @param index Variable is `index'th local variable on the method's frame + * @param constant_pool Array of constants + */ + public LocalVariable(int start_pc, int length, int name_index, int signature_index, int index, + ConstantPool constant_pool) { + this.start_pc = start_pc; + this.length = length; + this.name_index = name_index; + this.signature_index = signature_index; + this.index = index; + this.constant_pool = constant_pool; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitLocalVariable(this); + } + + + /** + * Dump local variable to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeShort(start_pc); + file.writeShort(length); + file.writeShort(name_index); + file.writeShort(signature_index); + file.writeShort(index); + } + + + /** + * @return Constant pool used by this object. + */ + public final ConstantPool getConstantPool() { + return constant_pool; + } + + + /** + * @return Variable is valid within getStartPC() .. getStartPC()+getLength() + */ + public final int getLength() { + return length; + } + + + /** + * @return Variable name. + */ + public final String getName() { + ConstantUtf8 c; + c = (ConstantUtf8) constant_pool.getConstant(name_index, CONSTANT_Utf8); + return c.getBytes(); + } + + + /** + * @return Index in constant pool of variable name. + */ + public final int getNameIndex() { + return name_index; + } + + + /** + * @return Signature. + */ + public final String getSignature() { + ConstantUtf8 c; + c = (ConstantUtf8) constant_pool.getConstant(signature_index, CONSTANT_Utf8); + return c.getBytes(); + } + + + /** + * @return Index in constant pool of variable signature. + */ + public final int getSignatureIndex() { + return signature_index; + } + + + /** + * @return index of register where variable is stored + */ + public final int getIndex() { + return index; + } + + + /** + * @return Start of range where he variable is valid + */ + public final int getStartPC() { + return start_pc; + } + + + /** + * @param constant_pool Constant pool to be used for this object. + */ + public final void setConstantPool( ConstantPool constant_pool ) { + this.constant_pool = constant_pool; + } + + + /** + * @param length the length of this local variable + */ + public final void setLength( int length ) { + this.length = length; + } + + + /** + * @param name_index the index into the constant pool for the name of this variable + */ + public final void setNameIndex( int name_index ) { + this.name_index = name_index; + } + + + /** + * @param signature_index the index into the constant pool for the signature of this variable + */ + public final void setSignatureIndex( int signature_index ) { + this.signature_index = signature_index; + } + + + /** + * @param index the index in the local variable table of this variable + */ + public final void setIndex( int index ) { + this.index = index; + } + + + /** + * @param start_pc Specify range where the local variable is valid. + */ + public final void setStartPC( int start_pc ) { + this.start_pc = start_pc; + } + + + /** + * @return string representation. + */ + public final String toString() { + String name = getName(), signature = Utility.signatureToString(getSignature()); + return "LocalVariable(start_pc = " + start_pc + ", length = " + length + ", index = " + + index + ":" + signature + " " + name + ")"; + } + + + /** + * @return deep copy of this object + */ + public LocalVariable copy() { + try { + return (LocalVariable) clone(); + } catch (CloneNotSupportedException e) { + } + return null; + } +} diff --git a/src/org/apache/bcel/classfile/LocalVariableTable.java b/src/org/apache/bcel/classfile/LocalVariableTable.java new file mode 100644 index 0000000..cbdc36c --- /dev/null +++ b/src/org/apache/bcel/classfile/LocalVariableTable.java @@ -0,0 +1,197 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class represents colection of local variables in a + * method. This attribute is contained in the Code attribute. + * + * @version $Id: LocalVariableTable.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Code + * @see LocalVariable + */ +public class LocalVariableTable extends Attribute { + + private int local_variable_table_length; // Table of local + private LocalVariable[] local_variable_table; // variables + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use copy() for a physical copy. + */ + public LocalVariableTable(LocalVariableTable c) { + this(c.getNameIndex(), c.getLength(), c.getLocalVariableTable(), c.getConstantPool()); + } + + + /** + * @param name_index Index in constant pool to `LocalVariableTable' + * @param length Content length in bytes + * @param local_variable_table Table of local variables + * @param constant_pool Array of constants + */ + public LocalVariableTable(int name_index, int length, LocalVariable[] local_variable_table, + ConstantPool constant_pool) { + super(Constants.ATTR_LOCAL_VARIABLE_TABLE, name_index, length, constant_pool); + setLocalVariableTable(local_variable_table); + } + + + /** + * Construct object from file stream. + * @param name_index Index in constant pool + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + LocalVariableTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, (LocalVariable[]) null, constant_pool); + local_variable_table_length = (file.readUnsignedShort()); + local_variable_table = new LocalVariable[local_variable_table_length]; + for (int i = 0; i < local_variable_table_length; i++) { + local_variable_table[i] = new LocalVariable(file, constant_pool); + } + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitLocalVariableTable(this); + } + + + /** + * Dump local variable table attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + file.writeShort(local_variable_table_length); + for (int i = 0; i < local_variable_table_length; i++) { + local_variable_table[i].dump(file); + } + } + + + /** + * @return Array of local variables of method. + */ + public final LocalVariable[] getLocalVariableTable() { + return local_variable_table; + } + + + /** + * @return first matching variable using index + * + * @param index the variable slot + * + * @return the first LocalVariable that matches the slot or null if not found + * + * @deprecated since 5.2 because multiple variables can share the + * same slot, use getLocalVariable(int index, int pc) instead. + */ + public final LocalVariable getLocalVariable( int index ) { + for (int i = 0; i < local_variable_table_length; i++) { + if (local_variable_table[i].getIndex() == index) { + return local_variable_table[i]; + } + } + return null; + } + + + /** + * @return matching variable using index when variable is used at supplied pc + * + * @param index the variable slot + * @param pc the current pc that this variable is alive + * + * @return the LocalVariable that matches or null if not found + */ + public final LocalVariable getLocalVariable( int index, int pc ) { + for (int i = 0; i < local_variable_table_length; i++) { + if (local_variable_table[i].getIndex() == index) { + int start_pc = local_variable_table[i].getStartPC(); + int end_pc = start_pc + local_variable_table[i].getLength(); + if ((pc >= start_pc) && (pc < end_pc)) { + return local_variable_table[i]; + } + } + } + return null; + } + + + public final void setLocalVariableTable( LocalVariable[] local_variable_table ) { + this.local_variable_table = local_variable_table; + local_variable_table_length = (local_variable_table == null) + ? 0 + : local_variable_table.length; + } + + + /** + * @return String representation. + */ + public final String toString() { + StringBuffer buf = new StringBuffer(""); + for (int i = 0; i < local_variable_table_length; i++) { + buf.append(local_variable_table[i].toString()); + if (i < local_variable_table_length - 1) { + buf.append('\n'); + } + } + return buf.toString(); + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + LocalVariableTable c = (LocalVariableTable) clone(); + c.local_variable_table = new LocalVariable[local_variable_table_length]; + for (int i = 0; i < local_variable_table_length; i++) { + c.local_variable_table[i] = local_variable_table[i].copy(); + } + c.constant_pool = _constant_pool; + return c; + } + + + public final int getTableLength() { + return local_variable_table_length; + } +} diff --git a/src/org/apache/bcel/classfile/Method.java b/src/org/apache/bcel/classfile/Method.java new file mode 100644 index 0000000..51b38ba --- /dev/null +++ b/src/org/apache/bcel/classfile/Method.java @@ -0,0 +1,254 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.IOException; +import org.apache.bcel.Constants; +import org.apache.bcel.generic.Type; +import org.apache.bcel.util.BCELComparator; + +/** + * This class represents the method info structure, i.e., the representation + * for a method in the class. See JVM specification for details. + * A method has access flags, a name, a signature and a number of attributes. + * + * @version $Id: Method.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class Method extends FieldOrMethod { + + private static BCELComparator _cmp = new BCELComparator() { + + public boolean equals( Object o1, Object o2 ) { + Method THIS = (Method) o1; + Method THAT = (Method) o2; + return THIS.getName().equals(THAT.getName()) + && THIS.getSignature().equals(THAT.getSignature()); + } + + + public int hashCode( Object o ) { + Method THIS = (Method) o; + return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + } + }; + + + /** + * Empty constructor, all attributes have to be defined via `setXXX' + * methods. Use at your own risk. + */ + public Method() { + } + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + public Method(Method c) { + super(c); + } + + + /** + * Construct object from file stream. + * @param file Input stream + * @throws IOException + * @throws ClassFormatException + */ + Method(DataInputStream file, ConstantPool constant_pool) throws IOException, + ClassFormatException { + super(file, constant_pool); + } + + + /** + * @param access_flags Access rights of method + * @param name_index Points to field name in constant pool + * @param signature_index Points to encoded signature + * @param attributes Collection of attributes + * @param constant_pool Array of constants + */ + public Method(int access_flags, int name_index, int signature_index, Attribute[] attributes, + ConstantPool constant_pool) { + super(access_flags, name_index, signature_index, attributes, constant_pool); + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitMethod(this); + } + + + /** + * @return Code attribute of method, if any + */ + public final Code getCode() { + for (int i = 0; i < attributes_count; i++) { + if (attributes[i] instanceof Code) { + return (Code) attributes[i]; + } + } + return null; + } + + + /** + * @return ExceptionTable attribute of method, if any, i.e., list all + * exceptions the method may throw not exception handlers! + */ + public final ExceptionTable getExceptionTable() { + for (int i = 0; i < attributes_count; i++) { + if (attributes[i] instanceof ExceptionTable) { + return (ExceptionTable) attributes[i]; + } + } + return null; + } + + + /** @return LocalVariableTable of code attribute if any, i.e. the call is forwarded + * to the Code atribute. + */ + public final LocalVariableTable getLocalVariableTable() { + Code code = getCode(); + if (code == null) { + return null; + } + return code.getLocalVariableTable(); + } + + + /** @return LineNumberTable of code attribute if any, i.e. the call is forwarded + * to the Code atribute. + */ + public final LineNumberTable getLineNumberTable() { + Code code = getCode(); + if (code == null) { + return null; + } + return code.getLineNumberTable(); + } + + + /** + * Return string representation close to declaration format, + * `public static void main(String[] args) throws IOException', e.g. + * + * @return String representation of the method. + */ + public final String toString() { + ConstantUtf8 c; + String name, signature, access; // Short cuts to constant pool + StringBuffer buf; + access = Utility.accessToString(access_flags); + // Get name and signature from constant pool + c = (ConstantUtf8) constant_pool.getConstant(signature_index, Constants.CONSTANT_Utf8); + signature = c.getBytes(); + c = (ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8); + name = c.getBytes(); + signature = Utility.methodSignatureToString(signature, name, access, true, + getLocalVariableTable()); + buf = new StringBuffer(signature); + for (int i = 0; i < attributes_count; i++) { + Attribute a = attributes[i]; + if (!((a instanceof Code) || (a instanceof ExceptionTable))) { + buf.append(" [").append(a.toString()).append("]"); + } + } + ExceptionTable e = getExceptionTable(); + if (e != null) { + String str = e.toString(); + if (!str.equals("")) { + buf.append("\n\t\tthrows ").append(str); + } + } + return buf.toString(); + } + + + /** + * @return deep copy of this method + */ + public final Method copy( ConstantPool _constant_pool ) { + return (Method) copy_(_constant_pool); + } + + + /** + * @return return type of method + */ + public Type getReturnType() { + return Type.getReturnType(getSignature()); + } + + + /** + * @return array of method argument types + */ + public Type[] getArgumentTypes() { + return Type.getArgumentTypes(getSignature()); + } + + + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return _cmp; + } + + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator( BCELComparator comparator ) { + _cmp = comparator; + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default two method objects are said to be equal when + * their names and signatures are equal. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals( Object obj ) { + return _cmp.equals(this, obj); + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default return the hashcode of the method's name XOR signature. + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return _cmp.hashCode(this); + } +} diff --git a/src/org/apache/bcel/classfile/Node.java b/src/org/apache/bcel/classfile/Node.java new file mode 100644 index 0000000..f105b7c --- /dev/null +++ b/src/org/apache/bcel/classfile/Node.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +/** + * Denote class to have an accept method(); + * + * @version $Id: Node.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface Node { + + public void accept( Visitor obj ); +} diff --git a/src/org/apache/bcel/classfile/PMGClass.java b/src/org/apache/bcel/classfile/PMGClass.java new file mode 100644 index 0000000..9511871 --- /dev/null +++ b/src/org/apache/bcel/classfile/PMGClass.java @@ -0,0 +1,167 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from Attribute and represents a reference + * to a PMG attribute. + * + * @version $Id: PMGClass.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Attribute + */ +public final class PMGClass extends Attribute { + + private int pmg_class_index, pmg_index; + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + public PMGClass(PMGClass c) { + this(c.getNameIndex(), c.getLength(), c.getPMGIndex(), c.getPMGClassIndex(), c + .getConstantPool()); + } + + + /** + * Construct object from file stream. + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + PMGClass(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, file.readUnsignedShort(), file.readUnsignedShort(), constant_pool); + } + + + /** + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param pmg_index index in constant pool for source file name + * @param pmg_class_index Index in constant pool to CONSTANT_Utf8 + * @param constant_pool Array of constants + */ + public PMGClass(int name_index, int length, int pmg_index, int pmg_class_index, + ConstantPool constant_pool) { + super(Constants.ATTR_PMG, name_index, length, constant_pool); + this.pmg_index = pmg_index; + this.pmg_class_index = pmg_class_index; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + System.err.println("Visiting non-standard PMGClass object"); + } + + + /** + * Dump source file attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + file.writeShort(pmg_index); + file.writeShort(pmg_class_index); + } + + + /** + * @return Index in constant pool of source file name. + */ + public final int getPMGClassIndex() { + return pmg_class_index; + } + + + /** + * @param pmg_class_index + */ + public final void setPMGClassIndex( int pmg_class_index ) { + this.pmg_class_index = pmg_class_index; + } + + + /** + * @return Index in constant pool of source file name. + */ + public final int getPMGIndex() { + return pmg_index; + } + + + /** + * @param pmg_index + */ + public final void setPMGIndex( int pmg_index ) { + this.pmg_index = pmg_index; + } + + + /** + * @return PMG name. + */ + public final String getPMGName() { + ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(pmg_index, + Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + + /** + * @return PMG class name. + */ + public final String getPMGClassName() { + ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(pmg_class_index, + Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + + /** + * @return String representation + */ + public final String toString() { + return "PMGClass(" + getPMGName() + ", " + getPMGClassName() + ")"; + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + return (PMGClass) clone(); + } +} diff --git a/src/org/apache/bcel/classfile/Signature.java b/src/org/apache/bcel/classfile/Signature.java new file mode 100644 index 0000000..49c03d4 --- /dev/null +++ b/src/org/apache/bcel/classfile/Signature.java @@ -0,0 +1,273 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from Attribute and represents a reference + * to a GJ attribute. + * + * @version $Id: Signature.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Attribute + */ +public final class Signature extends Attribute { + + private int signature_index; + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + public Signature(Signature c) { + this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool()); + } + + + /** + * Construct object from file stream. + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + Signature(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, file.readUnsignedShort(), constant_pool); + } + + + /** + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param signature_index Index in constant pool to CONSTANT_Utf8 + * @param constant_pool Array of constants + */ + public Signature(int name_index, int length, int signature_index, ConstantPool constant_pool) { + super(Constants.ATTR_SIGNATURE, name_index, length, constant_pool); + this.signature_index = signature_index; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + //System.err.println("Visiting non-standard Signature object"); + v.visitSignature(this); + } + + + /** + * Dump source file attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + file.writeShort(signature_index); + } + + + /** + * @return Index in constant pool of source file name. + */ + public final int getSignatureIndex() { + return signature_index; + } + + + /** + * @param signature_index the index info the constant pool of this signature + */ + public final void setSignatureIndex( int signature_index ) { + this.signature_index = signature_index; + } + + + /** + * @return GJ signature. + */ + public final String getSignature() { + ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(signature_index, + Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + /** + * Extends ByteArrayInputStream to make 'unreading' chars possible. + */ + private static final class MyByteArrayInputStream extends ByteArrayInputStream { + + MyByteArrayInputStream(String data) { + super(data.getBytes()); + } + + + final int mark() { + return pos; + } + + + final String getData() { + return new String(buf); + } + + + final void reset( int p ) { + pos = p; + } + + + final void unread() { + if (pos > 0) { + pos--; + } + } + } + + + private static boolean identStart( int ch ) { + return ch == 'T' || ch == 'L'; + } + + + private static final void matchIdent( MyByteArrayInputStream in, StringBuffer buf ) { + int ch; + if ((ch = in.read()) == -1) { + throw new RuntimeException("Illegal signature: " + in.getData() + + " no ident, reaching EOF"); + } + //System.out.println("return from ident:" + (char)ch); + if (!identStart(ch)) { + StringBuffer buf2 = new StringBuffer(); + int count = 1; + while (Character.isJavaIdentifierPart((char) ch)) { + buf2.append((char) ch); + count++; + ch = in.read(); + } + if (ch == ':') { // Ok, formal parameter + in.skip("Ljava/lang/Object".length()); + buf.append(buf2); + ch = in.read(); + in.unread(); + //System.out.println("so far:" + buf2 + ":next:" +(char)ch); + } else { + for (int i = 0; i < count; i++) { + in.unread(); + } + } + return; + } + StringBuffer buf2 = new StringBuffer(); + ch = in.read(); + do { + buf2.append((char) ch); + ch = in.read(); + //System.out.println("within ident:"+ (char)ch); + } while ((ch != -1) && (Character.isJavaIdentifierPart((char) ch) || (ch == '/'))); + buf.append(buf2.toString().replace('/', '.')); + //System.out.println("regular return ident:"+ (char)ch + ":" + buf2); + if (ch != -1) { + in.unread(); + } + } + + + private static final void matchGJIdent( MyByteArrayInputStream in, StringBuffer buf ) { + int ch; + matchIdent(in, buf); + ch = in.read(); + if ((ch == '<') || ch == '(') { // Parameterized or method + //System.out.println("Enter <"); + buf.append((char) ch); + matchGJIdent(in, buf); + while (((ch = in.read()) != '>') && (ch != ')')) { // List of parameters + if (ch == -1) { + throw new RuntimeException("Illegal signature: " + in.getData() + + " reaching EOF"); + } + //System.out.println("Still no >"); + buf.append(", "); + in.unread(); + matchGJIdent(in, buf); // Recursive call + } + //System.out.println("Exit >"); + buf.append((char) ch); + } else { + in.unread(); + } + ch = in.read(); + if (identStart(ch)) { + in.unread(); + matchGJIdent(in, buf); + } else if (ch == ')') { + in.unread(); + return; + } else if (ch != ';') { + throw new RuntimeException("Illegal signature: " + in.getData() + " read " + (char) ch); + } + } + + + public static String translate( String s ) { + //System.out.println("Sig:" + s); + StringBuffer buf = new StringBuffer(); + matchGJIdent(new MyByteArrayInputStream(s), buf); + return buf.toString(); + } + + + public static final boolean isFormalParameterList( String s ) { + return s.startsWith("<") && (s.indexOf(':') > 0); + } + + + public static final boolean isActualParameterList( String s ) { + return s.startsWith("L") && s.endsWith(">;"); + } + + + /** + * @return String representation + */ + public final String toString() { + String s = getSignature(); + return "Signature(" + s + ")"; + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + return (Signature) clone(); + } +} diff --git a/src/org/apache/bcel/classfile/SourceFile.java b/src/org/apache/bcel/classfile/SourceFile.java new file mode 100644 index 0000000..da391b4 --- /dev/null +++ b/src/org/apache/bcel/classfile/SourceFile.java @@ -0,0 +1,145 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from Attribute and represents a reference + * to the source file of this class. At most one SourceFile attribute + * should appear per classfile. The intention of this class is that it is + * instantiated from the Attribute.readAttribute() method. + * + * @version $Id: SourceFile.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Attribute + */ +public final class SourceFile extends Attribute { + + private int sourcefile_index; + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + public SourceFile(SourceFile c) { + this(c.getNameIndex(), c.getLength(), c.getSourceFileIndex(), c.getConstantPool()); + } + + + /** + * Construct object from file stream. + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + SourceFile(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, file.readUnsignedShort(), constant_pool); + } + + + /** + * @param name_index Index in constant pool to CONSTANT_Utf8, which + * should represent the string "SourceFile". + * @param length Content length in bytes, the value should be 2. + * @param constant_pool The constant pool that this attribute is + * associated with. + * @param sourcefile_index Index in constant pool to CONSTANT_Utf8. This + * string will be interpreted as the name of the file from which this + * class was compiled. It will not be interpreted as indicating the name + * of the directory contqining the file or an absolute path; this + * information has to be supplied the consumer of this attribute - in + * many cases, the JVM. + */ + public SourceFile(int name_index, int length, int sourcefile_index, ConstantPool constant_pool) { + super(Constants.ATTR_SOURCE_FILE, name_index, length, constant_pool); + this.sourcefile_index = sourcefile_index; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitSourceFile(this); + } + + + /** + * Dump source file attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + file.writeShort(sourcefile_index); + } + + + /** + * @return Index in constant pool of source file name. + */ + public final int getSourceFileIndex() { + return sourcefile_index; + } + + + /** + * @param sourcefile_index + */ + public final void setSourceFileIndex( int sourcefile_index ) { + this.sourcefile_index = sourcefile_index; + } + + + /** + * @return Source file name. + */ + public final String getSourceFileName() { + ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(sourcefile_index, + Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + + /** + * @return String representation + */ + public final String toString() { + return "SourceFile(" + getSourceFileName() + ")"; + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + return (SourceFile) clone(); + } +} diff --git a/src/org/apache/bcel/classfile/StackMap.java b/src/org/apache/bcel/classfile/StackMap.java new file mode 100644 index 0000000..75e695a --- /dev/null +++ b/src/org/apache/bcel/classfile/StackMap.java @@ -0,0 +1,153 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class represents a stack map attribute used for + * preverification of Java classes for the Java 2 Micro Edition + * (J2ME). This attribute is used by the KVM and contained + * within the Code attribute of a method. See CLDC specification + * 5.3.1.2 + * + * @version $Id: StackMap.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Code + * @see StackMapEntry + * @see StackMapType + */ +public final class StackMap extends Attribute implements Node { + + private int map_length; + private StackMapEntry[] map; // Table of stack map entries + + + /* + * @param name_index Index of name + * @param length Content length in bytes + * @param map Table of stack map entries + * @param constant_pool Array of constants + */ + public StackMap(int name_index, int length, StackMapEntry[] map, ConstantPool constant_pool) { + super(Constants.ATTR_STACK_MAP, name_index, length, constant_pool); + setStackMap(map); + } + + + /** + * Construct object from file stream. + * @param name_index Index of name + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + StackMap(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, (StackMapEntry[]) null, constant_pool); + map_length = file.readUnsignedShort(); + map = new StackMapEntry[map_length]; + for (int i = 0; i < map_length; i++) { + map[i] = new StackMapEntry(file, constant_pool); + } + } + + + /** + * Dump line number table attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + file.writeShort(map_length); + for (int i = 0; i < map_length; i++) { + map[i].dump(file); + } + } + + + /** + * @return Array of stack map entries + */ + public final StackMapEntry[] getStackMap() { + return map; + } + + + /** + * @param map Array of stack map entries + */ + public final void setStackMap( StackMapEntry[] map ) { + this.map = map; + map_length = (map == null) ? 0 : map.length; + } + + + /** + * @return String representation. + */ + public final String toString() { + StringBuffer buf = new StringBuffer("StackMap("); + for (int i = 0; i < map_length; i++) { + buf.append(map[i].toString()); + if (i < map_length - 1) { + buf.append(", "); + } + } + buf.append(')'); + return buf.toString(); + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + StackMap c = (StackMap) clone(); + c.map = new StackMapEntry[map_length]; + for (int i = 0; i < map_length; i++) { + c.map[i] = map[i].copy(); + } + c.constant_pool = _constant_pool; + return c; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackMap(this); + } + + + public final int getMapLength() { + return map_length; + } +} diff --git a/src/org/apache/bcel/classfile/StackMapEntry.java b/src/org/apache/bcel/classfile/StackMapEntry.java new file mode 100644 index 0000000..2d53152 --- /dev/null +++ b/src/org/apache/bcel/classfile/StackMapEntry.java @@ -0,0 +1,212 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * This class represents a stack map entry recording the types of + * local variables and the the of stack items at a given byte code offset. + * See CLDC specification 5.3.1.2 + * + * @version $Id: StackMapEntry.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see StackMap + * @see StackMapType + */ +public final class StackMapEntry implements Cloneable { + + private int byte_code_offset; + private int number_of_locals; + private StackMapType[] types_of_locals; + private int number_of_stack_items; + private StackMapType[] types_of_stack_items; + private ConstantPool constant_pool; + + + /** + * Construct object from file stream. + * @param file Input stream + * @throws IOException + */ + StackMapEntry(DataInputStream file, ConstantPool constant_pool) throws IOException { + this(file.readShort(), file.readShort(), null, -1, null, constant_pool); + types_of_locals = new StackMapType[number_of_locals]; + for (int i = 0; i < number_of_locals; i++) { + types_of_locals[i] = new StackMapType(file, constant_pool); + } + number_of_stack_items = file.readShort(); + types_of_stack_items = new StackMapType[number_of_stack_items]; + for (int i = 0; i < number_of_stack_items; i++) { + types_of_stack_items[i] = new StackMapType(file, constant_pool); + } + } + + + public StackMapEntry(int byte_code_offset, int number_of_locals, + StackMapType[] types_of_locals, int number_of_stack_items, + StackMapType[] types_of_stack_items, ConstantPool constant_pool) { + this.byte_code_offset = byte_code_offset; + this.number_of_locals = number_of_locals; + this.types_of_locals = types_of_locals; + this.number_of_stack_items = number_of_stack_items; + this.types_of_stack_items = types_of_stack_items; + this.constant_pool = constant_pool; + } + + + /** + * Dump stack map entry + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeShort(byte_code_offset); + file.writeShort(number_of_locals); + for (int i = 0; i < number_of_locals; i++) { + types_of_locals[i].dump(file); + } + file.writeShort(number_of_stack_items); + for (int i = 0; i < number_of_stack_items; i++) { + types_of_stack_items[i].dump(file); + } + } + + + /** + * @return String representation. + */ + public final String toString() { + StringBuffer buf = new StringBuffer(64); + buf.append("(offset=").append(byte_code_offset); + if (number_of_locals > 0) { + buf.append(", locals={"); + for (int i = 0; i < number_of_locals; i++) { + buf.append(types_of_locals[i]); + if (i < number_of_locals - 1) { + buf.append(", "); + } + } + buf.append("}"); + } + if (number_of_stack_items > 0) { + buf.append(", stack items={"); + for (int i = 0; i < number_of_stack_items; i++) { + buf.append(types_of_stack_items[i]); + if (i < number_of_stack_items - 1) { + buf.append(", "); + } + } + buf.append("}"); + } + buf.append(")"); + return buf.toString(); + } + + + public void setByteCodeOffset( int b ) { + byte_code_offset = b; + } + + + public int getByteCodeOffset() { + return byte_code_offset; + } + + + public void setNumberOfLocals( int n ) { + number_of_locals = n; + } + + + public int getNumberOfLocals() { + return number_of_locals; + } + + + public void setTypesOfLocals( StackMapType[] t ) { + types_of_locals = t; + } + + + public StackMapType[] getTypesOfLocals() { + return types_of_locals; + } + + + public void setNumberOfStackItems( int n ) { + number_of_stack_items = n; + } + + + public int getNumberOfStackItems() { + return number_of_stack_items; + } + + + public void setTypesOfStackItems( StackMapType[] t ) { + types_of_stack_items = t; + } + + + public StackMapType[] getTypesOfStackItems() { + return types_of_stack_items; + } + + + /** + * @return deep copy of this object + */ + public StackMapEntry copy() { + try { + return (StackMapEntry) clone(); + } catch (CloneNotSupportedException e) { + } + return null; + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackMapEntry(this); + } + + + /** + * @return Constant pool used by this object. + */ + public final ConstantPool getConstantPool() { + return constant_pool; + } + + + /** + * @param constant_pool Constant pool to be used for this object. + */ + public final void setConstantPool( ConstantPool constant_pool ) { + this.constant_pool = constant_pool; + } +} diff --git a/src/org/apache/bcel/classfile/StackMapType.java b/src/org/apache/bcel/classfile/StackMapType.java new file mode 100644 index 0000000..df6555e --- /dev/null +++ b/src/org/apache/bcel/classfile/StackMapType.java @@ -0,0 +1,161 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class represents the type of a local variable or item on stack + * used in the StackMap entries. + * + * @version $Id: StackMapType.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see StackMapEntry + * @see StackMap + * @see Constants + */ +public final class StackMapType implements Cloneable { + + private byte type; + private int index = -1; // Index to CONSTANT_Class or offset + private ConstantPool constant_pool; + + + /** + * Construct object from file stream. + * @param file Input stream + * @throws IOException + */ + StackMapType(DataInputStream file, ConstantPool constant_pool) throws IOException { + this(file.readByte(), -1, constant_pool); + if (hasIndex()) { + setIndex(file.readShort()); + } + setConstantPool(constant_pool); + } + + + /** + * @param type type tag as defined in the Constants interface + * @param index index to constant pool, or byte code offset + */ + public StackMapType(byte type, int index, ConstantPool constant_pool) { + setType(type); + setIndex(index); + setConstantPool(constant_pool); + } + + + public void setType( byte t ) { + if ((t < Constants.ITEM_Bogus) || (t > Constants.ITEM_NewObject)) { + throw new RuntimeException("Illegal type for StackMapType: " + t); + } + type = t; + } + + + public byte getType() { + return type; + } + + + public void setIndex( int t ) { + index = t; + } + + + /** @return index to constant pool if type == ITEM_Object, or offset + * in byte code, if type == ITEM_NewObject, and -1 otherwise + */ + public int getIndex() { + return index; + } + + + /** + * Dump type entries to file. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + file.writeByte(type); + if (hasIndex()) { + file.writeShort(getIndex()); + } + } + + + /** @return true, if type is either ITEM_Object or ITEM_NewObject + */ + public final boolean hasIndex() { + return ((type == Constants.ITEM_Object) || (type == Constants.ITEM_NewObject)); + } + + + private String printIndex() { + if (type == Constants.ITEM_Object) { + if (index < 0) { + return ", class="; + } + return ", class=" + constant_pool.constantToString(index, Constants.CONSTANT_Class); + } else if (type == Constants.ITEM_NewObject) { + return ", offset=" + index; + } else { + return ""; + } + } + + + /** + * @return String representation + */ + public final String toString() { + return "(type=" + Constants.ITEM_NAMES[type] + printIndex() + ")"; + } + + + /** + * @return deep copy of this object + */ + public StackMapType copy() { + try { + return (StackMapType) clone(); + } catch (CloneNotSupportedException e) { + } + return null; + } + + + /** + * @return Constant pool used by this object. + */ + public final ConstantPool getConstantPool() { + return constant_pool; + } + + + /** + * @param constant_pool Constant pool to be used for this object. + */ + public final void setConstantPool( ConstantPool constant_pool ) { + this.constant_pool = constant_pool; + } +} diff --git a/src/org/apache/bcel/classfile/Synthetic.java b/src/org/apache/bcel/classfile/Synthetic.java new file mode 100644 index 0000000..a7ce252 --- /dev/null +++ b/src/org/apache/bcel/classfile/Synthetic.java @@ -0,0 +1,150 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; + +/** + * This class is derived from Attribute and declares this class as + * `synthetic', i.e., it needs special handling. The JVM specification + * states "A class member that does not appear in the source code must be + * marked using a Synthetic attribute." It may appear in the ClassFile + * attribute table, a field_info table or a method_info table. This class + * is intended to be instantiated from the + * Attribute.readAttribute() method. + * + * @version $Id: Synthetic.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Attribute + */ +public final class Synthetic extends Attribute { + + private byte[] bytes; + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use copy() for a physical copy. + */ + public Synthetic(Synthetic c) { + this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool()); + } + + + /** + * @param name_index Index in constant pool to CONSTANT_Utf8, which + * should represent the string "Synthetic". + * @param length Content length in bytes - should be zero. + * @param bytes Attribute contents + * @param constant_pool The constant pool this attribute is associated + * with. + */ + public Synthetic(int name_index, int length, byte[] bytes, ConstantPool constant_pool) { + super(Constants.ATTR_SYNTHETIC, name_index, length, constant_pool); + this.bytes = bytes; + } + + + /** + * Construct object from file stream. + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + Synthetic(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, (byte[]) null, constant_pool); + if (length > 0) { + bytes = new byte[length]; + file.readFully(bytes); + System.err.println("Synthetic attribute with length > 0"); + } + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitSynthetic(this); + } + + + /** + * Dump source file attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + if (length > 0) { + file.write(bytes, 0, length); + } + } + + + /** + * @return data bytes. + */ + public final byte[] getBytes() { + return bytes; + } + + + /** + * @param bytes + */ + public final void setBytes( byte[] bytes ) { + this.bytes = bytes; + } + + + /** + * @return String representation. + */ + public final String toString() { + StringBuffer buf = new StringBuffer("Synthetic"); + if (length > 0) { + buf.append(" ").append(Utility.toHexString(bytes)); + } + return buf.toString(); + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + Synthetic c = (Synthetic) clone(); + if (bytes != null) { + c.bytes = new byte[bytes.length]; + System.arraycopy(bytes, 0, c.bytes, 0, bytes.length); + } + c.constant_pool = _constant_pool; + return c; + } +} diff --git a/src/org/apache/bcel/classfile/Unknown.java b/src/org/apache/bcel/classfile/Unknown.java new file mode 100644 index 0000000..d7e333e --- /dev/null +++ b/src/org/apache/bcel/classfile/Unknown.java @@ -0,0 +1,188 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.apache.bcel.Constants; + +/** + * This class represents a reference to an unknown (i.e., + * application-specific) attribute of a class. It is instantiated from the + * Attribute.readAttribute() method. Applications that need to + * read in application-specific attributes should create an AttributeReader implementation and + * attach it via Attribute.addAttributeReader. + + * + * @version $Id: Unknown.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @see org.apache.bcel.classfile.Attribute + * @see org.apache.bcel.classfile.AttributeReader + * @author M. Dahm + */ +public final class Unknown extends Attribute { + + private byte[] bytes; + private String name; + private static Map unknown_attributes = new HashMap(); + + + /** @return array of unknown attributes, but just one for each kind. + */ + static Unknown[] getUnknownAttributes() { + Unknown[] unknowns = new Unknown[unknown_attributes.size()]; + Iterator entries = unknown_attributes.values().iterator(); + for (int i = 0; entries.hasNext(); i++) { + unknowns[i] = (Unknown) entries.next(); + } + unknown_attributes.clear(); + return unknowns; + } + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + public Unknown(Unknown c) { + this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool()); + } + + + /** + * Create a non-standard attribute. + * + * @param name_index Index in constant pool + * @param length Content length in bytes + * @param bytes Attribute contents + * @param constant_pool Array of constants + */ + public Unknown(int name_index, int length, byte[] bytes, ConstantPool constant_pool) { + super(Constants.ATTR_UNKNOWN, name_index, length, constant_pool); + this.bytes = bytes; + name = ((ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8)) + .getBytes(); + unknown_attributes.put(name, this); + } + + + /** + * Construct object from file stream. + * @param name_index Index in constant pool + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + Unknown(int name_index, int length, DataInputStream file, ConstantPool constant_pool) + throws IOException { + this(name_index, length, (byte[]) null, constant_pool); + if (length > 0) { + bytes = new byte[length]; + file.readFully(bytes); + } + } + + + /** + * Called by objects that are traversing the nodes of the tree implicitely + * defined by the contents of a Java class. I.e., the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitUnknown(this); + } + + + /** + * Dump unknown bytes to file stream. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump( DataOutputStream file ) throws IOException { + super.dump(file); + if (length > 0) { + file.write(bytes, 0, length); + } + } + + + /** + * @return data bytes. + */ + public final byte[] getBytes() { + return bytes; + } + + + /** + * @return name of attribute. + */ + public final String getName() { + return name; + } + + + /** + * @param bytes the bytes to set + */ + public final void setBytes( byte[] bytes ) { + this.bytes = bytes; + } + + + /** + * @return String representation. + */ + public final String toString() { + if (length == 0 || bytes == null) { + return "(Unknown attribute " + name + ")"; + } + String hex; + if (length > 10) { + byte[] tmp = new byte[10]; + System.arraycopy(bytes, 0, tmp, 0, 10); + hex = Utility.toHexString(tmp) + "... (truncated)"; + } else { + hex = Utility.toHexString(bytes); + } + return "(Unknown attribute " + name + ": " + hex + ")"; + } + + + /** + * @return deep copy of this attribute + */ + public Attribute copy( ConstantPool _constant_pool ) { + Unknown c = (Unknown) clone(); + if (bytes != null) { + c.bytes = new byte[bytes.length]; + System.arraycopy(bytes, 0, c.bytes, 0, bytes.length); + } + c.constant_pool = _constant_pool; + return c; + } +} diff --git a/src/org/apache/bcel/classfile/Utility.java b/src/org/apache/bcel/classfile/Utility.java new file mode 100644 index 0000000..d9b79c1 --- /dev/null +++ b/src/org/apache/bcel/classfile/Utility.java @@ -0,0 +1,1342 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.CharArrayReader; +import java.io.CharArrayWriter; +import java.io.FilterReader; +import java.io.FilterWriter; +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; +import org.apache.bcel.Constants; +import org.apache.bcel.util.ByteSequence; + +/** + * Utility functions that do not really belong to any class in particular. + * + * @version $Id: Utility.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class Utility { + + private static int unwrap( ThreadLocal tl ) { + return ((Integer) tl.get()).intValue(); + } + + + private static void wrap( ThreadLocal tl, int value ) { + tl.set(new Integer(value)); + } + + private static ThreadLocal consumed_chars = new ThreadLocal() { + + protected Object initialValue() { + return new Integer(0); + } + };/* How many chars have been consumed + * during parsing in signatureToString(). + * Read by methodSignatureToString(). + * Set by side effect,but only internally. + */ + private static boolean wide = false; /* The `WIDE' instruction is used in the + * byte code to allow 16-bit wide indices + * for local variables. This opcode + * precedes an `ILOAD', e.g.. The opcode + * immediately following takes an extra + * byte which is combined with the + * following byte to form a + * 16-bit value. + */ + + + /** + * Convert bit field of flags into string such as `static final'. + * + * @param access_flags Access flags + * @return String representation of flags + */ + public static final String accessToString( int access_flags ) { + return accessToString(access_flags, false); + } + + + /** + * Convert bit field of flags into string such as `static final'. + * + * Special case: Classes compiled with new compilers and with the + * `ACC_SUPER' flag would be said to be "synchronized". This is + * because SUN used the same value for the flags `ACC_SUPER' and + * `ACC_SYNCHRONIZED'. + * + * @param access_flags Access flags + * @param for_class access flags are for class qualifiers ? + * @return String representation of flags + */ + public static final String accessToString( int access_flags, boolean for_class ) { + StringBuffer buf = new StringBuffer(); + int p = 0; + for (int i = 0; p < Constants.MAX_ACC_FLAG; i++) { // Loop through known flags + p = pow2(i); + if ((access_flags & p) != 0) { + /* Special case: Classes compiled with new compilers and with the + * `ACC_SUPER' flag would be said to be "synchronized". This is + * because SUN used the same value for the flags `ACC_SUPER' and + * `ACC_SYNCHRONIZED'. + */ + if (for_class && ((p == Constants.ACC_SUPER) || (p == Constants.ACC_INTERFACE))) { + continue; + } + buf.append(Constants.ACCESS_NAMES[i]).append(" "); + } + } + return buf.toString().trim(); + } + + + /** + * @return "class" or "interface", depending on the ACC_INTERFACE flag + */ + public static final String classOrInterface( int access_flags ) { + return ((access_flags & Constants.ACC_INTERFACE) != 0) ? "interface" : "class"; + } + + + /** + * Disassemble a byte array of JVM byte codes starting from code line + * `index' and return the disassembled string representation. Decode only + * `num' opcodes (including their operands), use -1 if you want to + * decompile everything. + * + * @param code byte code array + * @param constant_pool Array of constants + * @param index offset in `code' array + * (number of opcodes, not bytes!) + * @param length number of opcodes to decompile, -1 for all + * @param verbose be verbose, e.g. print constant pool index + * @return String representation of byte codes + */ + public static final String codeToString( byte[] code, ConstantPool constant_pool, int index, + int length, boolean verbose ) { + StringBuffer buf = new StringBuffer(code.length * 20); // Should be sufficient + ByteSequence stream = new ByteSequence(code); + try { + for (int i = 0; i < index; i++) { + codeToString(stream, constant_pool, verbose); + } + for (int i = 0; stream.available() > 0; i++) { + if ((length < 0) || (i < length)) { + String indices = fillup(stream.getIndex() + ":", 6, true, ' '); + buf.append(indices).append(codeToString(stream, constant_pool, verbose)) + .append('\n'); + } + } + } catch (IOException e) { + System.out.println(buf.toString()); + e.printStackTrace(); + throw new ClassFormatException("Byte code error: " + e); + } + return buf.toString(); + } + + + public static final String codeToString( byte[] code, ConstantPool constant_pool, int index, + int length ) { + return codeToString(code, constant_pool, index, length, true); + } + + + /** + * Disassemble a stream of byte codes and return the + * string representation. + * + * @param bytes stream of bytes + * @param constant_pool Array of constants + * @param verbose be verbose, e.g. print constant pool index + * @return String representation of byte code + */ + public static final String codeToString( ByteSequence bytes, ConstantPool constant_pool, + boolean verbose ) throws IOException { + short opcode = (short) bytes.readUnsignedByte(); + int default_offset = 0, low, high, npairs; + int index, vindex, constant; + int[] match, jump_table; + int no_pad_bytes = 0, offset; + StringBuffer buf = new StringBuffer(Constants.OPCODE_NAMES[opcode]); + /* Special case: Skip (0-3) padding bytes, i.e., the + * following bytes are 4-byte-aligned + */ + if ((opcode == Constants.TABLESWITCH) || (opcode == Constants.LOOKUPSWITCH)) { + int remainder = bytes.getIndex() % 4; + no_pad_bytes = (remainder == 0) ? 0 : 4 - remainder; + for (int i = 0; i < no_pad_bytes; i++) { + byte b; + if ((b = bytes.readByte()) != 0) { + System.err.println("Warning: Padding byte != 0 in " + + Constants.OPCODE_NAMES[opcode] + ":" + b); + } + } + // Both cases have a field default_offset in common + default_offset = bytes.readInt(); + } + switch (opcode) { + /* Table switch has variable length arguments. + */ + case Constants.TABLESWITCH: + low = bytes.readInt(); + high = bytes.readInt(); + offset = bytes.getIndex() - 12 - no_pad_bytes - 1; + default_offset += offset; + buf.append("\tdefault = ").append(default_offset).append(", low = ").append(low) + .append(", high = ").append(high).append("("); + jump_table = new int[high - low + 1]; + for (int i = 0; i < jump_table.length; i++) { + jump_table[i] = offset + bytes.readInt(); + buf.append(jump_table[i]); + if (i < jump_table.length - 1) { + buf.append(", "); + } + } + buf.append(")"); + break; + /* Lookup switch has variable length arguments. + */ + case Constants.LOOKUPSWITCH: { + npairs = bytes.readInt(); + offset = bytes.getIndex() - 8 - no_pad_bytes - 1; + match = new int[npairs]; + jump_table = new int[npairs]; + default_offset += offset; + buf.append("\tdefault = ").append(default_offset).append(", npairs = ").append( + npairs).append(" ("); + for (int i = 0; i < npairs; i++) { + match[i] = bytes.readInt(); + jump_table[i] = offset + bytes.readInt(); + buf.append("(").append(match[i]).append(", ").append(jump_table[i]).append(")"); + if (i < npairs - 1) { + buf.append(", "); + } + } + buf.append(")"); + } + break; + /* Two address bytes + offset from start of byte stream form the + * jump target + */ + case Constants.GOTO: + case Constants.IFEQ: + case Constants.IFGE: + case Constants.IFGT: + case Constants.IFLE: + case Constants.IFLT: + case Constants.JSR: + case Constants.IFNE: + case Constants.IFNONNULL: + case Constants.IFNULL: + case Constants.IF_ACMPEQ: + case Constants.IF_ACMPNE: + case Constants.IF_ICMPEQ: + case Constants.IF_ICMPGE: + case Constants.IF_ICMPGT: + case Constants.IF_ICMPLE: + case Constants.IF_ICMPLT: + case Constants.IF_ICMPNE: + buf.append("\t\t#").append((bytes.getIndex() - 1) + bytes.readShort()); + break; + /* 32-bit wide jumps + */ + case Constants.GOTO_W: + case Constants.JSR_W: + buf.append("\t\t#").append(((bytes.getIndex() - 1) + bytes.readInt())); + break; + /* Index byte references local variable (register) + */ + case Constants.ALOAD: + case Constants.ASTORE: + case Constants.DLOAD: + case Constants.DSTORE: + case Constants.FLOAD: + case Constants.FSTORE: + case Constants.ILOAD: + case Constants.ISTORE: + case Constants.LLOAD: + case Constants.LSTORE: + case Constants.RET: + if (wide) { + vindex = bytes.readUnsignedShort(); + wide = false; // Clear flag + } else { + vindex = bytes.readUnsignedByte(); + } + buf.append("\t\t%").append(vindex); + break; + /* + * Remember wide byte which is used to form a 16-bit address in the + * following instruction. Relies on that the method is called again with + * the following opcode. + */ + case Constants.WIDE: + wide = true; + buf.append("\t(wide)"); + break; + /* Array of basic type. + */ + case Constants.NEWARRAY: + buf.append("\t\t<").append(Constants.TYPE_NAMES[bytes.readByte()]).append(">"); + break; + /* Access object/class fields. + */ + case Constants.GETFIELD: + case Constants.GETSTATIC: + case Constants.PUTFIELD: + case Constants.PUTSTATIC: + index = bytes.readUnsignedShort(); + buf.append("\t\t").append( + constant_pool.constantToString(index, Constants.CONSTANT_Fieldref)).append( + (verbose ? " (" + index + ")" : "")); + break; + /* Operands are references to classes in constant pool + */ + case Constants.NEW: + case Constants.CHECKCAST: + buf.append("\t"); + case Constants.INSTANCEOF: + index = bytes.readUnsignedShort(); + buf.append("\t<").append( + constant_pool.constantToString(index, Constants.CONSTANT_Class)) + .append(">").append((verbose ? " (" + index + ")" : "")); + break; + /* Operands are references to methods in constant pool + */ + case Constants.INVOKESPECIAL: + case Constants.INVOKESTATIC: + case Constants.INVOKEVIRTUAL: + index = bytes.readUnsignedShort(); + buf.append("\t").append( + constant_pool.constantToString(index, Constants.CONSTANT_Methodref)) + .append((verbose ? " (" + index + ")" : "")); + break; + case Constants.INVOKEINTERFACE: + index = bytes.readUnsignedShort(); + int nargs = bytes.readUnsignedByte(); // historical, redundant + buf.append("\t").append( + constant_pool + .constantToString(index, Constants.CONSTANT_InterfaceMethodref)) + .append(verbose ? " (" + index + ")\t" : "").append(nargs).append("\t") + .append(bytes.readUnsignedByte()); // Last byte is a reserved space + break; + /* Operands are references to items in constant pool + */ + case Constants.LDC_W: + case Constants.LDC2_W: + index = bytes.readUnsignedShort(); + buf.append("\t\t").append( + constant_pool.constantToString(index, constant_pool.getConstant(index) + .getTag())).append((verbose ? " (" + index + ")" : "")); + break; + case Constants.LDC: + index = bytes.readUnsignedByte(); + buf.append("\t\t").append( + constant_pool.constantToString(index, constant_pool.getConstant(index) + .getTag())).append((verbose ? " (" + index + ")" : "")); + break; + /* Array of references. + */ + case Constants.ANEWARRAY: + index = bytes.readUnsignedShort(); + buf.append("\t\t<").append( + compactClassName(constant_pool.getConstantString(index, + Constants.CONSTANT_Class), false)).append(">").append( + (verbose ? " (" + index + ")" : "")); + break; + /* Multidimensional array of references. + */ + case Constants.MULTIANEWARRAY: { + index = bytes.readUnsignedShort(); + int dimensions = bytes.readUnsignedByte(); + buf.append("\t<").append( + compactClassName(constant_pool.getConstantString(index, + Constants.CONSTANT_Class), false)).append(">\t").append(dimensions) + .append((verbose ? " (" + index + ")" : "")); + } + break; + /* Increment local variable. + */ + case Constants.IINC: + if (wide) { + vindex = bytes.readUnsignedShort(); + constant = bytes.readShort(); + wide = false; + } else { + vindex = bytes.readUnsignedByte(); + constant = bytes.readByte(); + } + buf.append("\t\t%").append(vindex).append("\t").append(constant); + break; + default: + if (Constants.NO_OF_OPERANDS[opcode] > 0) { + for (int i = 0; i < Constants.TYPE_OF_OPERANDS[opcode].length; i++) { + buf.append("\t\t"); + switch (Constants.TYPE_OF_OPERANDS[opcode][i]) { + case Constants.T_BYTE: + buf.append(bytes.readByte()); + break; + case Constants.T_SHORT: + buf.append(bytes.readShort()); + break; + case Constants.T_INT: + buf.append(bytes.readInt()); + break; + default: // Never reached + System.err.println("Unreachable default case reached!"); + System.exit(-1); + } + } + } + } + return buf.toString(); + } + + + public static final String codeToString( ByteSequence bytes, ConstantPool constant_pool ) + throws IOException { + return codeToString(bytes, constant_pool, true); + } + + + /** + * Shorten long class names, java/lang/String becomes + * String. + * + * @param str The long class name + * @return Compacted class name + */ + public static final String compactClassName( String str ) { + return compactClassName(str, true); + } + + + /** + * Shorten long class name str, i.e., chop off the prefix, + * if the + * class name starts with this string and the flag chopit is true. + * Slashes / are converted to dots .. + * + * @param str The long class name + * @param prefix The prefix the get rid off + * @param chopit Flag that determines whether chopping is executed or not + * @return Compacted class name + */ + public static final String compactClassName( String str, String prefix, boolean chopit ) { + int len = prefix.length(); + str = str.replace('/', '.'); // Is `/' on all systems, even DOS + if (chopit) { + // If string starts with `prefix' and contains no further dots + if (str.startsWith(prefix) && (str.substring(len).indexOf('.') == -1)) { + str = str.substring(len); + } + } + return str; + } + + + /** + * Shorten long class names, java/lang/String becomes + * java.lang.String, + * e.g.. If chopit is true the prefix java.lang + * is also removed. + * + * @param str The long class name + * @param chopit Flag that determines whether chopping is executed or not + * @return Compacted class name + */ + public static final String compactClassName( String str, boolean chopit ) { + return compactClassName(str, "java.lang.", chopit); + } + + + /** + * @return `flag' with bit `i' set to 1 + */ + public static final int setBit( int flag, int i ) { + return flag | pow2(i); + } + + + /** + * @return `flag' with bit `i' set to 0 + */ + public static final int clearBit( int flag, int i ) { + int bit = pow2(i); + return (flag & bit) == 0 ? flag : flag ^ bit; + } + + + /** + * @return true, if bit `i' in `flag' is set + */ + public static final boolean isSet( int flag, int i ) { + return (flag & pow2(i)) != 0; + } + + + /** + * Converts string containing the method return and argument types + * to a byte code method signature. + * + * @param ret Return type of method + * @param argv Types of method arguments + * @return Byte code representation of method signature + */ + public final static String methodTypeToSignature( String ret, String[] argv ) + throws ClassFormatException { + StringBuffer buf = new StringBuffer("("); + String str; + if (argv != null) { + for (int i = 0; i < argv.length; i++) { + str = getSignature(argv[i]); + if (str.endsWith("V")) { + throw new ClassFormatException("Invalid type: " + argv[i]); + } + buf.append(str); + } + } + str = getSignature(ret); + buf.append(")").append(str); + return buf.toString(); + } + + + /** + * @param signature Method signature + * @return Array of argument types + * @throws ClassFormatException + */ + public static final String[] methodSignatureArgumentTypes( String signature ) + throws ClassFormatException { + return methodSignatureArgumentTypes(signature, true); + } + + + /** + * @param signature Method signature + * @param chopit Shorten class names ? + * @return Array of argument types + * @throws ClassFormatException + */ + public static final String[] methodSignatureArgumentTypes( String signature, boolean chopit ) + throws ClassFormatException { + List vec = new ArrayList(); + int index; + try { // Read all declarations between for `(' and `)' + if (signature.charAt(0) != '(') { + throw new ClassFormatException("Invalid method signature: " + signature); + } + index = 1; // current string position + while (signature.charAt(index) != ')') { + vec.add(signatureToString(signature.substring(index), chopit)); + //corrected concurrent private static field acess + index += unwrap(consumed_chars); // update position + } + } catch (StringIndexOutOfBoundsException e) { // Should never occur + throw new ClassFormatException("Invalid method signature: " + signature); + } + return (String[]) vec.toArray(new String[vec.size()]); + } + + + /** + * @param signature Method signature + * @return return type of method + * @throws ClassFormatException + */ + public static final String methodSignatureReturnType( String signature ) + throws ClassFormatException { + return methodSignatureReturnType(signature, true); + } + + + /** + * @param signature Method signature + * @param chopit Shorten class names ? + * @return return type of method + * @throws ClassFormatException + */ + public static final String methodSignatureReturnType( String signature, boolean chopit ) + throws ClassFormatException { + int index; + String type; + try { + // Read return type after `)' + index = signature.lastIndexOf(')') + 1; + type = signatureToString(signature.substring(index), chopit); + } catch (StringIndexOutOfBoundsException e) { // Should never occur + throw new ClassFormatException("Invalid method signature: " + signature); + } + return type; + } + + + /** + * Converts method signature to string with all class names compacted. + * + * @param signature to convert + * @param name of method + * @param access flags of method + * @return Human readable signature + */ + public static final String methodSignatureToString( String signature, String name, String access ) { + return methodSignatureToString(signature, name, access, true); + } + + + public static final String methodSignatureToString( String signature, String name, + String access, boolean chopit ) { + return methodSignatureToString(signature, name, access, chopit, null); + } + + + /** + * A return type signature represents the return value from a method. + * It is a series of bytes in the following grammar: + * + * ::= | V + * + * The character V indicates that the method returns no value. Otherwise, the + * signature indicates the type of the return value. + * An argument signature represents an argument passed to a method: + * + * ::= + * + * A method signature represents the arguments that the method expects, and + * the value that it returns. + * ::= () + * ::= * + * + * This method converts such a string into a Java type declaration like + * `void main(String[])' and throws a `ClassFormatException' when the parsed + * type is invalid. + * + * @param signature Method signature + * @param name Method name + * @param access Method access rights + * @return Java type declaration + * @throws ClassFormatException + */ + public static final String methodSignatureToString( String signature, String name, + String access, boolean chopit, LocalVariableTable vars ) throws ClassFormatException { + StringBuffer buf = new StringBuffer("("); + String type; + int index; + int var_index = (access.indexOf("static") >= 0) ? 0 : 1; + try { // Read all declarations between for `(' and `)' + if (signature.charAt(0) != '(') { + throw new ClassFormatException("Invalid method signature: " + signature); + } + index = 1; // current string position + while (signature.charAt(index) != ')') { + String param_type = signatureToString(signature.substring(index), chopit); + buf.append(param_type); + if (vars != null) { + LocalVariable l = vars.getLocalVariable(var_index); + if (l != null) { + buf.append(" ").append(l.getName()); + } + } else { + buf.append(" arg").append(var_index); + } + if ("double".equals(param_type) || "long".equals(param_type)) { + var_index += 2; + } else { + var_index++; + } + buf.append(", "); + //corrected concurrent private static field acess + index += unwrap(consumed_chars); // update position + } + index++; // update position + // Read return type after `)' + type = signatureToString(signature.substring(index), chopit); + } catch (StringIndexOutOfBoundsException e) { // Should never occur + throw new ClassFormatException("Invalid method signature: " + signature); + } + if (buf.length() > 1) { + buf.setLength(buf.length() - 2); + } + buf.append(")"); + return access + ((access.length() > 0) ? " " : "") + // May be an empty string + type + " " + name + buf.toString(); + } + + + // Guess what this does + private static final int pow2( int n ) { + return 1 << n; + } + + + /** + * Replace all occurences of old in str with new. + * + * @param str String to permute + * @param old String to be replaced + * @param new_ Replacement string + * @return new String object + */ + public static final String replace( String str, String old, String new_ ) { + int index, old_index; + StringBuffer buf = new StringBuffer(); + try { + if ((index = str.indexOf(old)) != -1) { // `old' found in str + old_index = 0; // String start offset + // While we have something to replace + while ((index = str.indexOf(old, old_index)) != -1) { + buf.append(str.substring(old_index, index)); // append prefix + buf.append(new_); // append replacement + old_index = index + old.length(); // Skip `old'.length chars + } + buf.append(str.substring(old_index)); // append rest of string + str = buf.toString(); + } + } catch (StringIndexOutOfBoundsException e) { // Should not occur + System.err.println(e); + } + return str; + } + + + /** + * Converts signature to string with all class names compacted. + * + * @param signature to convert + * @return Human readable signature + */ + public static final String signatureToString( String signature ) { + return signatureToString(signature, true); + } + + + /** + * The field signature represents the value of an argument to a function or + * the value of a variable. It is a series of bytes generated by the + * following grammar: + * + *
+     *  ::= 
+     *       ::= ||
+     *        ::= B|C|D|F|I|J|S|Z
+     *      ::= L;
+     *       ::= [
+     *
+     * The meaning of the base types is as follows:
+     * B byte signed byte
+     * C char character
+     * D double double precision IEEE float
+     * F float single precision IEEE float
+     * I int integer
+     * J long long integer
+     * L; ... an object of the given class
+     * S short signed short
+     * Z boolean true or false
+     * [ ... array
+     * 
+ * + * This method converts this string into a Java type declaration such as + * `String[]' and throws a `ClassFormatException' when the parsed type is + * invalid. + * + * @param signature Class signature + * @param chopit Flag that determines whether chopping is executed or not + * @return Java type declaration + * @throws ClassFormatException + */ + public static final String signatureToString( String signature, boolean chopit ) { + //corrected concurrent private static field acess + wrap(consumed_chars, 1); // This is the default, read just one char like `B' + try { + switch (signature.charAt(0)) { + case 'B': + return "byte"; + case 'C': + return "char"; + case 'D': + return "double"; + case 'F': + return "float"; + case 'I': + return "int"; + case 'J': + return "long"; + case 'L': { // Full class name + int index = signature.indexOf(';'); // Look for closing `;' + if (index < 0) { + throw new ClassFormatException("Invalid signature: " + signature); + } + //corrected concurrent private static field acess + wrap(consumed_chars, index + 1); // "Lblabla;" `L' and `;' are removed + return compactClassName(signature.substring(1, index), chopit); + } + case 'S': + return "short"; + case 'Z': + return "boolean"; + case '[': { // Array declaration + int n; + StringBuffer brackets; + String type; + int consumed_chars; // Shadows global var + brackets = new StringBuffer(); // Accumulate []'s + // Count opening brackets and look for optional size argument + for (n = 0; signature.charAt(n) == '['; n++) { + brackets.append("[]"); + } + consumed_chars = n; // Remember value + // The rest of the string denotes a `' + type = signatureToString(signature.substring(n), chopit); + //corrected concurrent private static field acess + //Utility.consumed_chars += consumed_chars; is replaced by: + int _temp = unwrap(Utility.consumed_chars) + consumed_chars; + wrap(Utility.consumed_chars, _temp); + return type + brackets.toString(); + } + case 'V': + return "void"; + default: + throw new ClassFormatException("Invalid signature: `" + signature + "'"); + } + } catch (StringIndexOutOfBoundsException e) { // Should never occur + throw new ClassFormatException("Invalid signature: " + e + ":" + signature); + } + } + + + /** Parse Java type such as "char", or "java.lang.String[]" and return the + * signature in byte code format, e.g. "C" or "[Ljava/lang/String;" respectively. + * + * @param type Java type + * @return byte code signature + */ + public static String getSignature( String type ) { + StringBuffer buf = new StringBuffer(); + char[] chars = type.toCharArray(); + boolean char_found = false, delim = false; + int index = -1; + loop: for (int i = 0; i < chars.length; i++) { + switch (chars[i]) { + case ' ': + case '\t': + case '\n': + case '\r': + case '\f': + if (char_found) { + delim = true; + } + break; + case '[': + if (!char_found) { + throw new RuntimeException("Illegal type: " + type); + } + index = i; + break loop; + default: + char_found = true; + if (!delim) { + buf.append(chars[i]); + } + } + } + int brackets = 0; + if (index > 0) { + brackets = countBrackets(type.substring(index)); + } + type = buf.toString(); + buf.setLength(0); + for (int i = 0; i < brackets; i++) { + buf.append('['); + } + boolean found = false; + for (int i = Constants.T_BOOLEAN; (i <= Constants.T_VOID) && !found; i++) { + if (Constants.TYPE_NAMES[i].equals(type)) { + found = true; + buf.append(Constants.SHORT_TYPE_NAMES[i]); + } + } + if (!found) { + buf.append('L').append(type.replace('.', '/')).append(';'); + } + return buf.toString(); + } + + + private static int countBrackets( String brackets ) { + char[] chars = brackets.toCharArray(); + int count = 0; + boolean open = false; + for (int i = 0; i < chars.length; i++) { + switch (chars[i]) { + case '[': + if (open) { + throw new RuntimeException("Illegally nested brackets:" + brackets); + } + open = true; + break; + case ']': + if (!open) { + throw new RuntimeException("Illegally nested brackets:" + brackets); + } + open = false; + count++; + break; + default: + // Don't care + } + } + if (open) { + throw new RuntimeException("Illegally nested brackets:" + brackets); + } + return count; + } + + + /** + * Return type of method signature as a byte value as defined in Constants + * + * @param signature in format described above + * @return type of method signature + * @see Constants + */ + public static final byte typeOfMethodSignature( String signature ) throws ClassFormatException { + int index; + try { + if (signature.charAt(0) != '(') { + throw new ClassFormatException("Invalid method signature: " + signature); + } + index = signature.lastIndexOf(')') + 1; + return typeOfSignature(signature.substring(index)); + } catch (StringIndexOutOfBoundsException e) { + throw new ClassFormatException("Invalid method signature: " + signature); + } + } + + + /** + * Return type of signature as a byte value as defined in Constants + * + * @param signature in format described above + * @return type of signature + * @see Constants + */ + public static final byte typeOfSignature( String signature ) throws ClassFormatException { + try { + switch (signature.charAt(0)) { + case 'B': + return Constants.T_BYTE; + case 'C': + return Constants.T_CHAR; + case 'D': + return Constants.T_DOUBLE; + case 'F': + return Constants.T_FLOAT; + case 'I': + return Constants.T_INT; + case 'J': + return Constants.T_LONG; + case 'L': + return Constants.T_REFERENCE; + case '[': + return Constants.T_ARRAY; + case 'V': + return Constants.T_VOID; + case 'Z': + return Constants.T_BOOLEAN; + case 'S': + return Constants.T_SHORT; + default: + throw new ClassFormatException("Invalid method signature: " + signature); + } + } catch (StringIndexOutOfBoundsException e) { + throw new ClassFormatException("Invalid method signature: " + signature); + } + } + + + /** Map opcode names to opcode numbers. E.g., return Constants.ALOAD for "aload" + */ + public static short searchOpcode( String name ) { + name = name.toLowerCase(Locale.ENGLISH); + for (short i = 0; i < Constants.OPCODE_NAMES.length; i++) { + if (Constants.OPCODE_NAMES[i].equals(name)) { + return i; + } + } + return -1; + } + + + /** + * Convert (signed) byte to (unsigned) short value, i.e., all negative + * values become positive. + */ + private static final short byteToShort( byte b ) { + return (b < 0) ? (short) (256 + b) : (short) b; + } + + + /** Convert bytes into hexidecimal string + * + * @return bytes as hexidecimal string, e.g. 00 FA 12 ... + */ + public static final String toHexString( byte[] bytes ) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + short b = byteToShort(bytes[i]); + String hex = Integer.toString(b, 0x10); + if (b < 0x10) { + buf.append('0'); + } + buf.append(hex); + if (i < bytes.length - 1) { + buf.append(' '); + } + } + return buf.toString(); + } + + + /** + * Return a string for an integer justified left or right and filled up with + * `fill' characters if necessary. + * + * @param i integer to format + * @param length length of desired string + * @param left_justify format left or right + * @param fill fill character + * @return formatted int + */ + public static final String format( int i, int length, boolean left_justify, char fill ) { + return fillup(Integer.toString(i), length, left_justify, fill); + } + + + /** + * Fillup char with up to length characters with char `fill' and justify it left or right. + * + * @param str string to format + * @param length length of desired string + * @param left_justify format left or right + * @param fill fill character + * @return formatted string + */ + public static final String fillup( String str, int length, boolean left_justify, char fill ) { + int len = length - str.length(); + char[] buf = new char[(len < 0) ? 0 : len]; + for (int j = 0; j < buf.length; j++) { + buf[j] = fill; + } + if (left_justify) { + return str + new String(buf); + } + return new String(buf) + str; + } + + + static final boolean equals( byte[] a, byte[] b ) { + int size; + if ((size = a.length) != b.length) { + return false; + } + for (int i = 0; i < size; i++) { + if (a[i] != b[i]) { + return false; + } + } + return true; + } + + + public static final void printArray( PrintStream out, Object[] obj ) { + out.println(printArray(obj, true)); + } + + + public static final void printArray( PrintWriter out, Object[] obj ) { + out.println(printArray(obj, true)); + } + + + public static final String printArray( Object[] obj ) { + return printArray(obj, true); + } + + + public static final String printArray( Object[] obj, boolean braces ) { + return printArray(obj, braces, false); + } + + + public static final String printArray( Object[] obj, boolean braces, boolean quote ) { + if (obj == null) { + return null; + } + StringBuffer buf = new StringBuffer(); + if (braces) { + buf.append('{'); + } + for (int i = 0; i < obj.length; i++) { + if (obj[i] != null) { + buf.append((quote ? "\"" : "")).append(obj[i].toString()).append( + (quote ? "\"" : "")); + } else { + buf.append("null"); + } + if (i < obj.length - 1) { + buf.append(", "); + } + } + if (braces) { + buf.append('}'); + } + return buf.toString(); + } + + + /** @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _) + */ + public static boolean isJavaIdentifierPart( char ch ) { + return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) + || ((ch >= '0') && (ch <= '9')) || (ch == '_'); + } + + + /** Encode byte array it into Java identifier string, i.e., a string + * that only contains the following characters: (a, ... z, A, ... Z, + * 0, ... 9, _, $). The encoding algorithm itself is not too + * clever: if the current byte's ASCII value already is a valid Java + * identifier part, leave it as it is. Otherwise it writes the + * escape character($) followed by

  • the ASCII value as a + * hexadecimal string, if the value is not in the range + * 200..247
  • a Java identifier char not used in a lowercase + * hexadecimal string, if the value is in the range + * 200..247
    • + * + *

      This operation inflates the original byte array by roughly 40-50%

      + * + * @param bytes the byte array to convert + * @param compress use gzip to minimize string + */ + public static String encode( byte[] bytes, boolean compress ) throws IOException { + if (compress) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream gos = new GZIPOutputStream(baos); + gos.write(bytes, 0, bytes.length); + gos.close(); + baos.close(); + bytes = baos.toByteArray(); + } + CharArrayWriter caw = new CharArrayWriter(); + JavaWriter jw = new JavaWriter(caw); + for (int i = 0; i < bytes.length; i++) { + int in = bytes[i] & 0x000000ff; // Normalize to unsigned + jw.write(in); + } + return caw.toString(); + } + + + /** Decode a string back to a byte array. + * + * @param s the string to convert + * @param uncompress use gzip to uncompress the stream of bytes + */ + public static byte[] decode( String s, boolean uncompress ) throws IOException { + char[] chars = s.toCharArray(); + CharArrayReader car = new CharArrayReader(chars); + JavaReader jr = new JavaReader(car); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + int ch; + while ((ch = jr.read()) >= 0) { + bos.write(ch); + } + bos.close(); + car.close(); + jr.close(); + byte[] bytes = bos.toByteArray(); + if (uncompress) { + GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(bytes)); + byte[] tmp = new byte[bytes.length * 3]; // Rough estimate + int count = 0; + int b; + while ((b = gis.read()) >= 0) { + tmp[count++] = (byte) b; + } + bytes = new byte[count]; + System.arraycopy(tmp, 0, bytes, 0, count); + } + return bytes; + } + + // A-Z, g-z, _, $ + private static final int FREE_CHARS = 48; + static int[] CHAR_MAP = new int[FREE_CHARS]; + static int[] MAP_CHAR = new int[256]; // Reverse map + private static final char ESCAPE_CHAR = '$'; + static { + int j = 0; + for (int i = 'A'; i <= 'Z'; i++) { + CHAR_MAP[j] = i; + MAP_CHAR[i] = j; + j++; + } + for (int i = 'g'; i <= 'z'; i++) { + CHAR_MAP[j] = i; + MAP_CHAR[i] = j; + j++; + } + CHAR_MAP[j] = '$'; + MAP_CHAR['$'] = j; + j++; + CHAR_MAP[j] = '_'; + MAP_CHAR['_'] = j; + } + + /** Decode characters into bytes. + * Used by decode() + */ + private static class JavaReader extends FilterReader { + + public JavaReader(Reader in) { + super(in); + } + + + public int read() throws IOException { + int b = in.read(); + if (b != ESCAPE_CHAR) { + return b; + } + int i = in.read(); + if (i < 0) { + return -1; + } + if (((i >= '0') && (i <= '9')) || ((i >= 'a') && (i <= 'f'))) { // Normal escape + int j = in.read(); + if (j < 0) { + return -1; + } + char[] tmp = { + (char) i, (char) j + }; + int s = Integer.parseInt(new String(tmp), 16); + return s; + } + return MAP_CHAR[i]; + } + + + public int read( char[] cbuf, int off, int len ) throws IOException { + for (int i = 0; i < len; i++) { + cbuf[off + i] = (char) read(); + } + return len; + } + } + + /** Encode bytes into valid java identifier characters. + * Used by encode() + */ + private static class JavaWriter extends FilterWriter { + + public JavaWriter(Writer out) { + super(out); + } + + + public void write( int b ) throws IOException { + if (isJavaIdentifierPart((char) b) && (b != ESCAPE_CHAR)) { + out.write(b); + } else { + out.write(ESCAPE_CHAR); // Escape character + // Special escape + if (b >= 0 && b < FREE_CHARS) { + out.write(CHAR_MAP[b]); + } else { // Normal escape + char[] tmp = Integer.toHexString(b).toCharArray(); + if (tmp.length == 1) { + out.write('0'); + out.write(tmp[0]); + } else { + out.write(tmp[0]); + out.write(tmp[1]); + } + } + } + } + + + public void write( char[] cbuf, int off, int len ) throws IOException { + for (int i = 0; i < len; i++) { + write(cbuf[off + i]); + } + } + + + public void write( String str, int off, int len ) throws IOException { + write(str.toCharArray(), off, len); + } + } + + + /** + * Escape all occurences of newline chars '\n', quotes \", etc. + */ + public static final String convertString( String label ) { + char[] ch = label.toCharArray(); + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < ch.length; i++) { + switch (ch[i]) { + case '\n': + buf.append("\\n"); + break; + case '\r': + buf.append("\\r"); + break; + case '\"': + buf.append("\\\""); + break; + case '\'': + buf.append("\\'"); + break; + case '\\': + buf.append("\\\\"); + break; + default: + buf.append(ch[i]); + break; + } + } + return buf.toString(); + } +} diff --git a/src/org/apache/bcel/classfile/Visitor.java b/src/org/apache/bcel/classfile/Visitor.java new file mode 100644 index 0000000..4eda18b --- /dev/null +++ b/src/org/apache/bcel/classfile/Visitor.java @@ -0,0 +1,127 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.classfile; + +/** + * Interface to make use of the Visitor pattern programming style. + * I.e. a class that implements this interface can traverse the contents of + * a Java class just by calling the `accept' method which all classes have. + * + * @version $Id: Visitor.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface Visitor { + + //public void visitAnnotation(Annotations obj); + //public void visitParameterAnnotation(ParameterAnnotations obj); + //public void visitAnnotationEntry(AnnotationEntry obj); + //public void visitAnnotationDefault(AnnotationDefault obj); + public void visitCode( Code obj ); + + + public void visitCodeException( CodeException obj ); + + + public void visitConstantClass( ConstantClass obj ); + + + public void visitConstantDouble( ConstantDouble obj ); + + + public void visitConstantFieldref( ConstantFieldref obj ); + + + public void visitConstantFloat( ConstantFloat obj ); + + + public void visitConstantInteger( ConstantInteger obj ); + + + public void visitConstantInterfaceMethodref( ConstantInterfaceMethodref obj ); + + + public void visitConstantLong( ConstantLong obj ); + + + public void visitConstantMethodref( ConstantMethodref obj ); + + + public void visitConstantNameAndType( ConstantNameAndType obj ); + + + public void visitConstantPool( ConstantPool obj ); + + + public void visitConstantString( ConstantString obj ); + + + public void visitConstantUtf8( ConstantUtf8 obj ); + + + public void visitConstantValue( ConstantValue obj ); + + + public void visitDeprecated( Deprecated obj ); + + + public void visitExceptionTable( ExceptionTable obj ); + + + public void visitField( Field obj ); + + + public void visitInnerClass( InnerClass obj ); + + + public void visitInnerClasses( InnerClasses obj ); + + + public void visitJavaClass( JavaClass obj ); + + + public void visitLineNumber( LineNumber obj ); + + + public void visitLineNumberTable( LineNumberTable obj ); + + + public void visitLocalVariable( LocalVariable obj ); + + + public void visitLocalVariableTable( LocalVariableTable obj ); + + + public void visitMethod( Method obj ); + + + public void visitSignature( Signature obj ); + + + public void visitSourceFile( SourceFile obj ); + + + public void visitSynthetic( Synthetic obj ); + + + public void visitUnknown( Unknown obj ); + + + public void visitStackMap( StackMap obj ); + + + public void visitStackMapEntry( StackMapEntry obj ); +} diff --git a/src/org/apache/bcel/classfile/package.html b/src/org/apache/bcel/classfile/package.html new file mode 100644 index 0000000..472c399 --- /dev/null +++ b/src/org/apache/bcel/classfile/package.html @@ -0,0 +1,14 @@ + + + + + + +

      +This package contains the classes that describe the structure of a +Java class file and a class file parser. +

      + + diff --git a/src/org/apache/bcel/generic/AALOAD.java b/src/org/apache/bcel/generic/AALOAD.java new file mode 100644 index 0000000..7668759 --- /dev/null +++ b/src/org/apache/bcel/generic/AALOAD.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * AALOAD - Load reference from array + *
      Stack: ..., arrayref, index -> value
      + * + * @version $Id: AALOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class AALOAD extends ArrayInstruction implements StackProducer { + + /** Load reference from array + */ + public AALOAD() { + super(org.apache.bcel.Constants.AALOAD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitAALOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/AASTORE.java b/src/org/apache/bcel/generic/AASTORE.java new file mode 100644 index 0000000..e445189 --- /dev/null +++ b/src/org/apache/bcel/generic/AASTORE.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * AASTORE - Store into reference array + *
      Stack: ..., arrayref, index, value -> ...
      + * + * @version $Id: AASTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class AASTORE extends ArrayInstruction implements StackConsumer { + + /** Store into reference array + */ + public AASTORE() { + super(org.apache.bcel.Constants.AASTORE); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitAASTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/ACONST_NULL.java b/src/org/apache/bcel/generic/ACONST_NULL.java new file mode 100644 index 0000000..d62d483 --- /dev/null +++ b/src/org/apache/bcel/generic/ACONST_NULL.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ACONST_NULL - Push null reference + *
      Stack: ... -> ..., null
      + * + * @version $Id: ACONST_NULL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ACONST_NULL extends Instruction implements PushInstruction, TypedInstruction { + + /** + * Push null reference + */ + public ACONST_NULL() { + super(org.apache.bcel.Constants.ACONST_NULL, (short) 1); + } + + + /** @return Type.NULL + */ + public Type getType( ConstantPoolGen cp ) { + return Type.NULL; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitPushInstruction(this); + v.visitTypedInstruction(this); + v.visitACONST_NULL(this); + } +} diff --git a/src/org/apache/bcel/generic/ALOAD.java b/src/org/apache/bcel/generic/ALOAD.java new file mode 100644 index 0000000..c093f5d --- /dev/null +++ b/src/org/apache/bcel/generic/ALOAD.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ALOAD - Load reference from local variable + *
      Stack: ... -> ..., objectref
      + * + * @version $Id: ALOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ALOAD extends LoadInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + ALOAD() { + super(org.apache.bcel.Constants.ALOAD, org.apache.bcel.Constants.ALOAD_0); + } + + + /** Load reference from local variable + * @param n index of local variable + */ + public ALOAD(int n) { + super(org.apache.bcel.Constants.ALOAD, org.apache.bcel.Constants.ALOAD_0, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + super.accept(v); + v.visitALOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/ANEWARRAY.java b/src/org/apache/bcel/generic/ANEWARRAY.java new file mode 100644 index 0000000..0d1d46a --- /dev/null +++ b/src/org/apache/bcel/generic/ANEWARRAY.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.ExceptionConstants; + +/** + * ANEWARRAY - Create new array of references + *
      Stack: ..., count -> ..., arrayref
      + * + * @version $Id: ANEWARRAY.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ANEWARRAY extends CPInstruction implements LoadClass, AllocationInstruction, + ExceptionThrower, StackConsumer, StackProducer { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + ANEWARRAY() { + } + + + public ANEWARRAY(int index) { + super(org.apache.bcel.Constants.ANEWARRAY, index); + } + + + public Class[] getExceptions() { + Class[] cs = new Class[1 + ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length); + cs[ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length] = ExceptionConstants.NEGATIVE_ARRAY_SIZE_EXCEPTION; + return cs; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitLoadClass(this); + v.visitAllocationInstruction(this); + v.visitExceptionThrower(this); + v.visitStackProducer(this); + v.visitTypedInstruction(this); + v.visitCPInstruction(this); + v.visitANEWARRAY(this); + } + + + public ObjectType getLoadClassType( ConstantPoolGen cpg ) { + Type t = getType(cpg); + if (t instanceof ArrayType) { + t = ((ArrayType) t).getBasicType(); + } + return (t instanceof ObjectType) ? (ObjectType) t : null; + } +} diff --git a/src/org/apache/bcel/generic/ARETURN.java b/src/org/apache/bcel/generic/ARETURN.java new file mode 100644 index 0000000..40dcee7 --- /dev/null +++ b/src/org/apache/bcel/generic/ARETURN.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ARETURN - Return reference from method + *
      Stack: ..., objectref -> <empty>
      + * + * @version $Id: ARETURN.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ARETURN extends ReturnInstruction { + + /** + * Return reference from method + */ + public ARETURN() { + super(org.apache.bcel.Constants.ARETURN); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitReturnInstruction(this); + v.visitARETURN(this); + } +} diff --git a/src/org/apache/bcel/generic/ARRAYLENGTH.java b/src/org/apache/bcel/generic/ARRAYLENGTH.java new file mode 100644 index 0000000..9c7ed7b --- /dev/null +++ b/src/org/apache/bcel/generic/ARRAYLENGTH.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ARRAYLENGTH - Get length of array + *
      Stack: ..., arrayref -> ..., length
      + * + * @version $Id: ARRAYLENGTH.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ARRAYLENGTH extends Instruction implements ExceptionThrower, StackProducer { + + /** Get length of array + */ + public ARRAYLENGTH() { + super(org.apache.bcel.Constants.ARRAYLENGTH, (short) 1); + } + + + /** @return exceptions this instruction may cause + */ + public Class[] getExceptions() { + return new Class[] { + org.apache.bcel.ExceptionConstants.NULL_POINTER_EXCEPTION + }; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitStackProducer(this); + v.visitARRAYLENGTH(this); + } +} diff --git a/src/org/apache/bcel/generic/ASTORE.java b/src/org/apache/bcel/generic/ASTORE.java new file mode 100644 index 0000000..351de5f --- /dev/null +++ b/src/org/apache/bcel/generic/ASTORE.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ASTORE - Store reference into local variable + *
      Stack ..., objectref -> ... 
      + * + * @version $Id: ASTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ASTORE extends StoreInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + ASTORE() { + super(org.apache.bcel.Constants.ASTORE, org.apache.bcel.Constants.ASTORE_0); + } + + + /** Store reference into local variable + * @param n index of local variable + */ + public ASTORE(int n) { + super(org.apache.bcel.Constants.ASTORE, org.apache.bcel.Constants.ASTORE_0, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + super.accept(v); + v.visitASTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/ATHROW.java b/src/org/apache/bcel/generic/ATHROW.java new file mode 100644 index 0000000..4694fbb --- /dev/null +++ b/src/org/apache/bcel/generic/ATHROW.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ATHROW - Throw exception + *
      Stack: ..., objectref -> objectref
      + * + * @version $Id: ATHROW.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ATHROW extends Instruction implements UnconditionalBranch, ExceptionThrower { + + /** + * Throw exception + */ + public ATHROW() { + super(org.apache.bcel.Constants.ATHROW, (short) 1); + } + + + /** @return exceptions this instruction may cause + */ + public Class[] getExceptions() { + return new Class[] { + org.apache.bcel.ExceptionConstants.THROWABLE + }; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitUnconditionalBranch(this); + v.visitExceptionThrower(this); + v.visitATHROW(this); + } +} diff --git a/src/org/apache/bcel/generic/AllocationInstruction.java b/src/org/apache/bcel/generic/AllocationInstruction.java new file mode 100644 index 0000000..652b887 --- /dev/null +++ b/src/org/apache/bcel/generic/AllocationInstruction.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denote family of instructions that allocates space in the heap. + * + * @version $Id: AllocationInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface AllocationInstruction { +} diff --git a/src/org/apache/bcel/generic/ArithmeticInstruction.java b/src/org/apache/bcel/generic/ArithmeticInstruction.java new file mode 100644 index 0000000..6edb5f3 --- /dev/null +++ b/src/org/apache/bcel/generic/ArithmeticInstruction.java @@ -0,0 +1,94 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; + +/** + * Super class for the family of arithmetic instructions. + * + * @version $Id: ArithmeticInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class ArithmeticInstruction extends Instruction implements TypedInstruction, + StackProducer, StackConsumer { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + ArithmeticInstruction() { + } + + + /** + * @param opcode of instruction + */ + protected ArithmeticInstruction(short opcode) { + super(opcode, (short) 1); + } + + + /** @return type associated with the instruction + */ + public Type getType( ConstantPoolGen cp ) { + switch (opcode) { + case Constants.DADD: + case Constants.DDIV: + case Constants.DMUL: + case Constants.DNEG: + case Constants.DREM: + case Constants.DSUB: + return Type.DOUBLE; + case Constants.FADD: + case Constants.FDIV: + case Constants.FMUL: + case Constants.FNEG: + case Constants.FREM: + case Constants.FSUB: + return Type.FLOAT; + case Constants.IADD: + case Constants.IAND: + case Constants.IDIV: + case Constants.IMUL: + case Constants.INEG: + case Constants.IOR: + case Constants.IREM: + case Constants.ISHL: + case Constants.ISHR: + case Constants.ISUB: + case Constants.IUSHR: + case Constants.IXOR: + return Type.INT; + case Constants.LADD: + case Constants.LAND: + case Constants.LDIV: + case Constants.LMUL: + case Constants.LNEG: + case Constants.LOR: + case Constants.LREM: + case Constants.LSHL: + case Constants.LSHR: + case Constants.LSUB: + case Constants.LUSHR: + case Constants.LXOR: + return Type.LONG; + default: // Never reached + throw new ClassGenException("Unknown type " + opcode); + } + } +} diff --git a/src/org/apache/bcel/generic/ArrayInstruction.java b/src/org/apache/bcel/generic/ArrayInstruction.java new file mode 100644 index 0000000..29bfd08 --- /dev/null +++ b/src/org/apache/bcel/generic/ArrayInstruction.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Super class for instructions dealing with array access such as IALOAD. + * + * @version $Id: ArrayInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class ArrayInstruction extends Instruction implements ExceptionThrower, + TypedInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + ArrayInstruction() { + } + + + /** + * @param opcode of instruction + */ + protected ArrayInstruction(short opcode) { + super(opcode, (short) 1); + } + + + public Class[] getExceptions() { + return org.apache.bcel.ExceptionConstants.EXCS_ARRAY_EXCEPTION; + } + + + /** @return type associated with the instruction + */ + public Type getType( ConstantPoolGen cp ) { + switch (opcode) { + case org.apache.bcel.Constants.IALOAD: + case org.apache.bcel.Constants.IASTORE: + return Type.INT; + case org.apache.bcel.Constants.CALOAD: + case org.apache.bcel.Constants.CASTORE: + return Type.CHAR; + case org.apache.bcel.Constants.BALOAD: + case org.apache.bcel.Constants.BASTORE: + return Type.BYTE; + case org.apache.bcel.Constants.SALOAD: + case org.apache.bcel.Constants.SASTORE: + return Type.SHORT; + case org.apache.bcel.Constants.LALOAD: + case org.apache.bcel.Constants.LASTORE: + return Type.LONG; + case org.apache.bcel.Constants.DALOAD: + case org.apache.bcel.Constants.DASTORE: + return Type.DOUBLE; + case org.apache.bcel.Constants.FALOAD: + case org.apache.bcel.Constants.FASTORE: + return Type.FLOAT; + case org.apache.bcel.Constants.AALOAD: + case org.apache.bcel.Constants.AASTORE: + return Type.OBJECT; + default: + throw new ClassGenException("Oops: unknown case in switch" + opcode); + } + } +} diff --git a/src/org/apache/bcel/generic/ArrayType.java b/src/org/apache/bcel/generic/ArrayType.java new file mode 100644 index 0000000..1750e25 --- /dev/null +++ b/src/org/apache/bcel/generic/ArrayType.java @@ -0,0 +1,127 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; + +/** + * Denotes array type, such as int[][] + * + * @version $Id: ArrayType.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class ArrayType extends ReferenceType { + + private int dimensions; + private Type basic_type; + + + /** + * Convenience constructor for array type, e.g. int[] + * + * @param type array type, e.g. T_INT + */ + public ArrayType(byte type, int dimensions) { + this(BasicType.getType(type), dimensions); + } + + + /** + * Convenience constructor for reference array type, e.g. Object[] + * + * @param class_name complete name of class (java.lang.String, e.g.) + */ + public ArrayType(String class_name, int dimensions) { + this(new ObjectType(class_name), dimensions); + } + + + /** + * Constructor for array of given type + * + * @param type type of array (may be an array itself) + */ + public ArrayType(Type type, int dimensions) { + super(Constants.T_ARRAY, ""); + if ((dimensions < 1) || (dimensions > Constants.MAX_BYTE)) { + throw new ClassGenException("Invalid number of dimensions: " + dimensions); + } + switch (type.getType()) { + case Constants.T_ARRAY: + ArrayType array = (ArrayType) type; + this.dimensions = dimensions + array.dimensions; + basic_type = array.basic_type; + break; + case Constants.T_VOID: + throw new ClassGenException("Invalid type: void[]"); + default: // Basic type or reference + this.dimensions = dimensions; + basic_type = type; + break; + } + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < this.dimensions; i++) { + buf.append('['); + } + buf.append(basic_type.getSignature()); + signature = buf.toString(); + } + + + /** + * @return basic type of array, i.e., for int[][][] the basic type is int + */ + public Type getBasicType() { + return basic_type; + } + + + /** + * @return element type of array, i.e., for int[][][] the element type is int[][] + */ + public Type getElementType() { + if (dimensions == 1) { + return basic_type; + } + return new ArrayType(basic_type, dimensions - 1); + } + + + /** @return number of dimensions of array + */ + public int getDimensions() { + return dimensions; + } + + + /** @return a hash code value for the object. + */ + public int hashCode() { + return basic_type.hashCode() ^ dimensions; + } + + + /** @return true if both type objects refer to the same array type. + */ + public boolean equals( Object _type ) { + if (_type instanceof ArrayType) { + ArrayType array = (ArrayType) _type; + return (array.dimensions == dimensions) && array.basic_type.equals(basic_type); + } + return false; + } +} diff --git a/src/org/apache/bcel/generic/BALOAD.java b/src/org/apache/bcel/generic/BALOAD.java new file mode 100644 index 0000000..e664378 --- /dev/null +++ b/src/org/apache/bcel/generic/BALOAD.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * BALOAD - Load byte or boolean from array + *
      Stack: ..., arrayref, index -> ..., value
      + * + * @version $Id: BALOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class BALOAD extends ArrayInstruction implements StackProducer { + + /** Load byte or boolean from array + */ + public BALOAD() { + super(org.apache.bcel.Constants.BALOAD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitBALOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/BASTORE.java b/src/org/apache/bcel/generic/BASTORE.java new file mode 100644 index 0000000..86e5889 --- /dev/null +++ b/src/org/apache/bcel/generic/BASTORE.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * BASTORE - Store into byte or boolean array + *
      Stack: ..., arrayref, index, value -> ...
      + * + * @version $Id: BASTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class BASTORE extends ArrayInstruction implements StackConsumer { + + /** Store byte or boolean into array + */ + public BASTORE() { + super(org.apache.bcel.Constants.BASTORE); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitBASTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/BIPUSH.java b/src/org/apache/bcel/generic/BIPUSH.java new file mode 100644 index 0000000..93c1a7b --- /dev/null +++ b/src/org/apache/bcel/generic/BIPUSH.java @@ -0,0 +1,105 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * BIPUSH - Push byte on stack + * + *
      Stack: ... -> ..., value
      + * + * @version $Id: BIPUSH.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class BIPUSH extends Instruction implements ConstantPushInstruction { + + private byte b; + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + BIPUSH() { + } + + + /** Push byte on stack + */ + public BIPUSH(byte b) { + super(org.apache.bcel.Constants.BIPUSH, (short) 2); + this.b = b; + } + + + /** + * Dump instruction as byte code to stream out. + */ + public void dump( DataOutputStream out ) throws IOException { + super.dump(out); + out.writeByte(b); + } + + + /** + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + return super.toString(verbose) + " " + b; + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + length = 2; + b = bytes.readByte(); + } + + + public Number getValue() { + return new Integer(b); + } + + + /** @return Type.BYTE + */ + public Type getType( ConstantPoolGen cp ) { + return Type.BYTE; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitPushInstruction(this); + v.visitStackProducer(this); + v.visitTypedInstruction(this); + v.visitConstantPushInstruction(this); + v.visitBIPUSH(this); + } +} diff --git a/src/org/apache/bcel/generic/BREAKPOINT.java b/src/org/apache/bcel/generic/BREAKPOINT.java new file mode 100644 index 0000000..ceb39cb --- /dev/null +++ b/src/org/apache/bcel/generic/BREAKPOINT.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * BREAKPOINT, JVM dependent, ignored by default + * + * @version $Id: BREAKPOINT.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class BREAKPOINT extends Instruction { + + public BREAKPOINT() { + super(org.apache.bcel.Constants.BREAKPOINT, (short) 1); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitBREAKPOINT(this); + } +} diff --git a/src/org/apache/bcel/generic/BasicType.java b/src/org/apache/bcel/generic/BasicType.java new file mode 100644 index 0000000..664a65f --- /dev/null +++ b/src/org/apache/bcel/generic/BasicType.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; + +/** + * Denotes basic type such as int. + * + * @version $Id: BasicType.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class BasicType extends Type { + + /** + * Constructor for basic types such as int, long, `void' + * + * @param type one of T_INT, T_BOOLEAN, ..., T_VOID + * @see org.apache.bcel.Constants + */ + BasicType(byte type) { + super(type, Constants.SHORT_TYPE_NAMES[type]); + if ((type < Constants.T_BOOLEAN) || (type > Constants.T_VOID)) { + throw new ClassGenException("Invalid type: " + type); + } + } + + + public static final BasicType getType( byte type ) { + switch (type) { + case Constants.T_VOID: + return VOID; + case Constants.T_BOOLEAN: + return BOOLEAN; + case Constants.T_BYTE: + return BYTE; + case Constants.T_SHORT: + return SHORT; + case Constants.T_CHAR: + return CHAR; + case Constants.T_INT: + return INT; + case Constants.T_LONG: + return LONG; + case Constants.T_DOUBLE: + return DOUBLE; + case Constants.T_FLOAT: + return FLOAT; + default: + throw new ClassGenException("Invalid type: " + type); + } + } + + + /** @return a hash code value for the object. + */ + public int hashCode() { + return type; + } + + + /** @return true if both type objects refer to the same type + */ + public boolean equals( Object _type ) { + return (_type instanceof BasicType) ? ((BasicType) _type).type == this.type : false; + } +} diff --git a/src/org/apache/bcel/generic/BranchHandle.java b/src/org/apache/bcel/generic/BranchHandle.java new file mode 100644 index 0000000..094678c --- /dev/null +++ b/src/org/apache/bcel/generic/BranchHandle.java @@ -0,0 +1,121 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * BranchHandle is returned by specialized InstructionList.append() whenever a + * BranchInstruction is appended. This is useful when the target of this + * instruction is not known at time of creation and must be set later + * via setTarget(). + * + * @see InstructionHandle + * @see Instruction + * @see InstructionList + * @version $Id: BranchHandle.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class BranchHandle extends InstructionHandle { + + private BranchInstruction bi; // An alias in fact, but saves lots of casts + + + private BranchHandle(BranchInstruction i) { + super(i); + bi = i; + } + + /** Factory methods. + */ + private static BranchHandle bh_list = null; // List of reusable handles + + + static final BranchHandle getBranchHandle( BranchInstruction i ) { + if (bh_list == null) { + return new BranchHandle(i); + } + BranchHandle bh = bh_list; + bh_list = (BranchHandle) bh.next; + bh.setInstruction(i); + return bh; + } + + + /** Handle adds itself to the list of resuable handles. + */ + protected void addHandle() { + next = bh_list; + bh_list = this; + } + + + /* Override InstructionHandle methods: delegate to branch instruction. + * Through this overriding all access to the private i_position field should + * be prevented. + */ + public int getPosition() { + return bi.position; + } + + + void setPosition( int pos ) { + i_position = bi.position = pos; + } + + + protected int updatePosition( int offset, int max_offset ) { + int x = bi.updatePosition(offset, max_offset); + i_position = bi.position; + return x; + } + + + /** + * Pass new target to instruction. + */ + public void setTarget( InstructionHandle ih ) { + bi.setTarget(ih); + } + + + /** + * Update target of instruction. + */ + public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ) { + bi.updateTarget(old_ih, new_ih); + } + + + /** + * @return target of instruction. + */ + public InstructionHandle getTarget() { + return bi.getTarget(); + } + + + /** + * Set new contents. Old instruction is disposed and may not be used anymore. + */ + public void setInstruction( Instruction i ) { + super.setInstruction(i); + if (!(i instanceof BranchInstruction)) { + throw new ClassGenException("Assigning " + i + + " to branch handle which is not a branch instruction"); + } + bi = (BranchInstruction) i; + } +} diff --git a/src/org/apache/bcel/generic/BranchInstruction.java b/src/org/apache/bcel/generic/BranchInstruction.java new file mode 100644 index 0000000..f62b831 --- /dev/null +++ b/src/org/apache/bcel/generic/BranchInstruction.java @@ -0,0 +1,230 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * Abstract super class for branching instructions like GOTO, IFEQ, etc.. + * Branch instructions may have a variable length, namely GOTO, JSR, + * LOOKUPSWITCH and TABLESWITCH. + * + * @see InstructionList + * @version $Id: BranchInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class BranchInstruction extends Instruction implements InstructionTargeter { + + protected int index; // Branch target relative to this instruction + protected InstructionHandle target; // Target object in instruction list + protected int position; // Byte code offset + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + BranchInstruction() { + } + + + /** Common super constructor + * @param opcode Instruction opcode + * @param target instruction to branch to + */ + protected BranchInstruction(short opcode, InstructionHandle target) { + super(opcode, (short) 3); + setTarget(target); + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + out.writeByte(opcode); + index = getTargetOffset(); + if (Math.abs(index) >= 32767) { + throw new ClassGenException("Branch target offset too large for short"); + } + out.writeShort(index); // May be negative, i.e., point backwards + } + + + /** + * @param _target branch target + * @return the offset to `target' relative to this instruction + */ + protected int getTargetOffset( InstructionHandle _target ) { + if (_target == null) { + throw new ClassGenException("Target of " + super.toString(true) + + " is invalid null handle"); + } + int t = _target.getPosition(); + if (t < 0) { + throw new ClassGenException("Invalid branch target position offset for " + + super.toString(true) + ":" + t + ":" + _target); + } + return t - position; + } + + + /** + * @return the offset to this instruction's target + */ + protected int getTargetOffset() { + return getTargetOffset(target); + } + + + /** + * Called by InstructionList.setPositions when setting the position for every + * instruction. In the presence of variable length instructions `setPositions' + * performs multiple passes over the instruction list to calculate the + * correct (byte) positions and offsets by calling this function. + * + * @param offset additional offset caused by preceding (variable length) instructions + * @param max_offset the maximum offset that may be caused by these instructions + * @return additional offset caused by possible change of this instruction's length + */ + protected int updatePosition( int offset, int max_offset ) { + position += offset; + return 0; + } + + + /** + * Long output format: + * + * <position in byte code> + * <name of opcode> "["<opcode number>"]" + * "("<length of instruction>")" + * "<"<target instruction>">" "@"<branch target offset> + * + * @param verbose long/short format switch + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + String s = super.toString(verbose); + String t = "null"; + if (verbose) { + if (target != null) { + if (target.getInstruction() == this) { + t = ""; + } else if (target.getInstruction() == null) { + t = ""; + } else { + t = target.getInstruction().toString(false); // Avoid circles + } + } + } else { + if (target != null) { + index = getTargetOffset(); + t = "" + (index + position); + } + } + return s + " -> " + t; + } + + + /** + * Read needed data (e.g. index) from file. Conversion to a InstructionHandle + * is done in InstructionList(byte[]). + * + * @param bytes input stream + * @param wide wide prefix? + * @see InstructionList + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + length = 3; + index = bytes.readShort(); + } + + + /** + * @return target offset in byte code + */ + public final int getIndex() { + return index; + } + + + /** + * @return target of branch instruction + */ + public InstructionHandle getTarget() { + return target; + } + + + /** + * Set branch target + * @param target branch target + */ + public void setTarget( InstructionHandle target ) { + notifyTarget(this.target, target, this); + this.target = target; + } + + + /** + * Used by BranchInstruction, LocalVariableGen, CodeExceptionGen + */ + static final void notifyTarget( InstructionHandle old_ih, InstructionHandle new_ih, + InstructionTargeter t ) { + if (old_ih != null) { + old_ih.removeTargeter(t); + } + if (new_ih != null) { + new_ih.addTargeter(t); + } + } + + + /** + * @param old_ih old target + * @param new_ih new target + */ + public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ) { + if (target == old_ih) { + setTarget(new_ih); + } else { + throw new ClassGenException("Not targeting " + old_ih + ", but " + target); + } + } + + + /** + * @return true, if ih is target of this instruction + */ + public boolean containsTarget( InstructionHandle ih ) { + return (target == ih); + } + + + /** + * Inform target that it's not targeted anymore. + */ + void dispose() { + setTarget(null); + index = -1; + position = -1; + } +} diff --git a/src/org/apache/bcel/generic/CALOAD.java b/src/org/apache/bcel/generic/CALOAD.java new file mode 100644 index 0000000..c3b1f31 --- /dev/null +++ b/src/org/apache/bcel/generic/CALOAD.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * CALOAD - Load char from array + *
      Stack: ..., arrayref, index -> ..., value
      + * + * @version $Id: CALOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class CALOAD extends ArrayInstruction implements StackProducer { + + /** Load char from array + */ + public CALOAD() { + super(org.apache.bcel.Constants.CALOAD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitCALOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/CASTORE.java b/src/org/apache/bcel/generic/CASTORE.java new file mode 100644 index 0000000..f293881 --- /dev/null +++ b/src/org/apache/bcel/generic/CASTORE.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * CASTORE - Store into char array + *
      Stack: ..., arrayref, index, value -> ...
      + * + * @version $Id: CASTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class CASTORE extends ArrayInstruction implements StackConsumer { + + /** Store char into array + */ + public CASTORE() { + super(org.apache.bcel.Constants.CASTORE); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitCASTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/CHECKCAST.java b/src/org/apache/bcel/generic/CHECKCAST.java new file mode 100644 index 0000000..7f6cfe3 --- /dev/null +++ b/src/org/apache/bcel/generic/CHECKCAST.java @@ -0,0 +1,84 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.ExceptionConstants; + +/** + * CHECKCAST - Check whether object is of given type + *
      Stack: ..., objectref -> ..., objectref
      + * + * @version $Id: CHECKCAST.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class CHECKCAST extends CPInstruction implements LoadClass, ExceptionThrower, StackProducer, + StackConsumer { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + CHECKCAST() { + } + + + /** Check whether object is of given type + * @param index index to class in constant pool + */ + public CHECKCAST(int index) { + super(org.apache.bcel.Constants.CHECKCAST, index); + } + + + /** @return exceptions this instruction may cause + */ + public Class[] getExceptions() { + Class[] cs = new Class[1 + ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length); + cs[ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length] = ExceptionConstants.CLASS_CAST_EXCEPTION; + return cs; + } + + + public ObjectType getLoadClassType( ConstantPoolGen cpg ) { + Type t = getType(cpg); + if (t instanceof ArrayType) { + t = ((ArrayType) t).getBasicType(); + } + return (t instanceof ObjectType) ? (ObjectType) t : null; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitLoadClass(this); + v.visitExceptionThrower(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitTypedInstruction(this); + v.visitCPInstruction(this); + v.visitCHECKCAST(this); + } +} diff --git a/src/org/apache/bcel/generic/CPInstruction.java b/src/org/apache/bcel/generic/CPInstruction.java new file mode 100644 index 0000000..9f988f9 --- /dev/null +++ b/src/org/apache/bcel/generic/CPInstruction.java @@ -0,0 +1,138 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.classfile.ConstantClass; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.util.ByteSequence; + +/** + * Abstract super class for instructions that use an index into the + * constant pool such as LDC, INVOKEVIRTUAL, etc. + * + * @see ConstantPoolGen + * @see LDC + * @see INVOKEVIRTUAL + * + * @version $Id: CPInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class CPInstruction extends Instruction implements TypedInstruction, + IndexedInstruction { + + protected int index; // index to constant pool + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + CPInstruction() { + } + + + /** + * @param index to constant pool + */ + protected CPInstruction(short opcode, int index) { + super(opcode, (short) 3); + setIndex(index); + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + out.writeByte(opcode); + out.writeShort(index); + } + + + /** + * Long output format: + * + * <name of opcode> "["<opcode number>"]" + * "("<length of instruction>")" "<"< constant pool index>">" + * + * @param verbose long/short format switch + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + return super.toString(verbose) + " " + index; + } + + + /** + * @return mnemonic for instruction with symbolic references resolved + */ + public String toString( ConstantPool cp ) { + Constant c = cp.getConstant(index); + String str = cp.constantToString(c); + if (c instanceof ConstantClass) { + str = str.replace('.', '/'); + } + return org.apache.bcel.Constants.OPCODE_NAMES[opcode] + " " + str; + } + + + /** + * Read needed data (i.e., index) from file. + * @param bytes input stream + * @param wide wide prefix? + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + setIndex(bytes.readUnsignedShort()); + length = 3; + } + + + /** + * @return index in constant pool referred by this instruction. + */ + public final int getIndex() { + return index; + } + + + /** + * Set the index to constant pool. + * @param index in constant pool. + */ + public void setIndex( int index ) { + if (index < 0) { + throw new ClassGenException("Negative index value: " + index); + } + this.index = index; + } + + + /** @return type related with this instruction. + */ + public Type getType( ConstantPoolGen cpg ) { + ConstantPool cp = cpg.getConstantPool(); + String name = cp.getConstantString(index, org.apache.bcel.Constants.CONSTANT_Class); + if (!name.startsWith("[")) { + name = "L" + name + ";"; + } + return Type.getType(name); + } +} diff --git a/src/org/apache/bcel/generic/ClassGen.java b/src/org/apache/bcel/generic/ClassGen.java new file mode 100644 index 0000000..14c48d3 --- /dev/null +++ b/src/org/apache/bcel/generic/ClassGen.java @@ -0,0 +1,541 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.AccessFlags; +import org.apache.bcel.classfile.Attribute; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.SourceFile; +import org.apache.bcel.util.BCELComparator; + +/** + * Template class for building up a java class. May be initialized with an + * existing java class (file). + * + * @see JavaClass + * @version $Id: ClassGen.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ClassGen extends AccessFlags implements Cloneable { + + /* Corresponds to the fields found in a JavaClass object. + */ + private String class_name, super_class_name, file_name; + private int class_name_index = -1, superclass_name_index = -1; + private int major = Constants.MAJOR_1_1, minor = Constants.MINOR_1_1; + private ConstantPoolGen cp; // Template for building up constant pool + // ArrayLists instead of arrays to gather fields, methods, etc. + private List field_vec = new ArrayList(); + private List method_vec = new ArrayList(); + private List attribute_vec = new ArrayList(); + private List interface_vec = new ArrayList(); + private static BCELComparator _cmp = new BCELComparator() { + + public boolean equals( Object o1, Object o2 ) { + ClassGen THIS = (ClassGen) o1; + ClassGen THAT = (ClassGen) o2; + return THIS.getClassName().equals(THAT.getClassName()); + } + + + public int hashCode( Object o ) { + ClassGen THIS = (ClassGen) o; + return THIS.getClassName().hashCode(); + } + }; + + + /** Convenience constructor to set up some important values initially. + * + * @param class_name fully qualified class name + * @param super_class_name fully qualified superclass name + * @param file_name source file name + * @param access_flags access qualifiers + * @param interfaces implemented interfaces + * @param cp constant pool to use + */ + public ClassGen(String class_name, String super_class_name, String file_name, int access_flags, + String[] interfaces, ConstantPoolGen cp) { + this.class_name = class_name; + this.super_class_name = super_class_name; + this.file_name = file_name; + this.access_flags = access_flags; + this.cp = cp; + // Put everything needed by default into the constant pool and the vectors + if (file_name != null) { + addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2, cp.addUtf8(file_name), cp + .getConstantPool())); + } + class_name_index = cp.addClass(class_name); + superclass_name_index = cp.addClass(super_class_name); + if (interfaces != null) { + for (int i = 0; i < interfaces.length; i++) { + addInterface(interfaces[i]); + } + } + } + + + /** Convenience constructor to set up some important values initially. + * + * @param class_name fully qualified class name + * @param super_class_name fully qualified superclass name + * @param file_name source file name + * @param access_flags access qualifiers + * @param interfaces implemented interfaces + */ + public ClassGen(String class_name, String super_class_name, String file_name, int access_flags, + String[] interfaces) { + this(class_name, super_class_name, file_name, access_flags, interfaces, + new ConstantPoolGen()); + } + + + /** + * Initialize with existing class. + * @param clazz JavaClass object (e.g. read from file) + */ + public ClassGen(JavaClass clazz) { + class_name_index = clazz.getClassNameIndex(); + superclass_name_index = clazz.getSuperclassNameIndex(); + class_name = clazz.getClassName(); + super_class_name = clazz.getSuperclassName(); + file_name = clazz.getSourceFileName(); + access_flags = clazz.getAccessFlags(); + cp = new ConstantPoolGen(clazz.getConstantPool()); + major = clazz.getMajor(); + minor = clazz.getMinor(); + Attribute[] attributes = clazz.getAttributes(); + Method[] methods = clazz.getMethods(); + Field[] fields = clazz.getFields(); + String[] interfaces = clazz.getInterfaceNames(); + for (int i = 0; i < interfaces.length; i++) { + addInterface(interfaces[i]); + } + for (int i = 0; i < attributes.length; i++) { + addAttribute(attributes[i]); + } + for (int i = 0; i < methods.length; i++) { + addMethod(methods[i]); + } + for (int i = 0; i < fields.length; i++) { + addField(fields[i]); + } + } + + + /** + * @return the (finally) built up Java class object. + */ + public JavaClass getJavaClass() { + int[] interfaces = getInterfaces(); + Field[] fields = getFields(); + Method[] methods = getMethods(); + Attribute[] attributes = getAttributes(); + // Must be last since the above calls may still add something to it + ConstantPool _cp = this.cp.getFinalConstantPool(); + return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor, + access_flags, _cp, interfaces, fields, methods, attributes); + } + + + /** + * Add an interface to this class, i.e., this class has to implement it. + * @param name interface to implement (fully qualified class name) + */ + public void addInterface( String name ) { + interface_vec.add(name); + } + + + /** + * Remove an interface from this class. + * @param name interface to remove (fully qualified name) + */ + public void removeInterface( String name ) { + interface_vec.remove(name); + } + + + /** + * @return major version number of class file + */ + public int getMajor() { + return major; + } + + + /** Set major version number of class file, default value is 45 (JDK 1.1) + * @param major major version number + */ + public void setMajor( int major ) { + this.major = major; + } + + + /** Set minor version number of class file, default value is 3 (JDK 1.1) + * @param minor minor version number + */ + public void setMinor( int minor ) { + this.minor = minor; + } + + + /** + * @return minor version number of class file + */ + public int getMinor() { + return minor; + } + + + /** + * Add an attribute to this class. + * @param a attribute to add + */ + public void addAttribute( Attribute a ) { + attribute_vec.add(a); + } + + + /** + * Add a method to this class. + * @param m method to add + */ + public void addMethod( Method m ) { + method_vec.add(m); + } + + + /** + * Convenience method. + * + * Add an empty constructor to this class that does nothing but calling super(). + * @param access_flags rights for constructor + */ + public void addEmptyConstructor( int access_flags ) { + InstructionList il = new InstructionList(); + il.append(InstructionConstants.THIS); // Push `this' + il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name, "", "()V"))); + il.append(InstructionConstants.RETURN); + MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, "", + class_name, il, cp); + mg.setMaxStack(1); + addMethod(mg.getMethod()); + } + + + /** + * Add a field to this class. + * @param f field to add + */ + public void addField( Field f ) { + field_vec.add(f); + } + + + public boolean containsField( Field f ) { + return field_vec.contains(f); + } + + + /** @return field object with given name, or null + */ + public Field containsField( String name ) { + for (Iterator e = field_vec.iterator(); e.hasNext();) { + Field f = (Field) e.next(); + if (f.getName().equals(name)) { + return f; + } + } + return null; + } + + + /** @return method object with given name and signature, or null + */ + public Method containsMethod( String name, String signature ) { + for (Iterator e = method_vec.iterator(); e.hasNext();) { + Method m = (Method) e.next(); + if (m.getName().equals(name) && m.getSignature().equals(signature)) { + return m; + } + } + return null; + } + + + /** + * Remove an attribute from this class. + * @param a attribute to remove + */ + public void removeAttribute( Attribute a ) { + attribute_vec.remove(a); + } + + + /** + * Remove a method from this class. + * @param m method to remove + */ + public void removeMethod( Method m ) { + method_vec.remove(m); + } + + + /** Replace given method with new one. If the old one does not exist + * add the new_ method to the class anyway. + */ + public void replaceMethod( Method old, Method new_ ) { + if (new_ == null) { + throw new ClassGenException("Replacement method must not be null"); + } + int i = method_vec.indexOf(old); + if (i < 0) { + method_vec.add(new_); + } else { + method_vec.set(i, new_); + } + } + + + /** Replace given field with new one. If the old one does not exist + * add the new_ field to the class anyway. + */ + public void replaceField( Field old, Field new_ ) { + if (new_ == null) { + throw new ClassGenException("Replacement method must not be null"); + } + int i = field_vec.indexOf(old); + if (i < 0) { + field_vec.add(new_); + } else { + field_vec.set(i, new_); + } + } + + + /** + * Remove a field to this class. + * @param f field to remove + */ + public void removeField( Field f ) { + field_vec.remove(f); + } + + + public String getClassName() { + return class_name; + } + + + public String getSuperclassName() { + return super_class_name; + } + + + public String getFileName() { + return file_name; + } + + + public void setClassName( String name ) { + class_name = name.replace('/', '.'); + class_name_index = cp.addClass(name); + } + + + public void setSuperclassName( String name ) { + super_class_name = name.replace('/', '.'); + superclass_name_index = cp.addClass(name); + } + + + public Method[] getMethods() { + return (Method[]) method_vec.toArray(new Method[method_vec.size()]); + } + + + public void setMethods( Method[] methods ) { + method_vec.clear(); + for (int m = 0; m < methods.length; m++) { + addMethod(methods[m]); + } + } + + + public void setMethodAt( Method method, int pos ) { + method_vec.set(pos, method); + } + + + public Method getMethodAt( int pos ) { + return (Method) method_vec.get(pos); + } + + + public String[] getInterfaceNames() { + int size = interface_vec.size(); + String[] interfaces = new String[size]; + interface_vec.toArray(interfaces); + return interfaces; + } + + + public int[] getInterfaces() { + int size = interface_vec.size(); + int[] interfaces = new int[size]; + for (int i = 0; i < size; i++) { + interfaces[i] = cp.addClass((String) interface_vec.get(i)); + } + return interfaces; + } + + + public Field[] getFields() { + return (Field[]) field_vec.toArray(new Field[field_vec.size()]); + } + + + public Attribute[] getAttributes() { + return (Attribute[]) attribute_vec.toArray(new Attribute[attribute_vec.size()]); + } + + + public ConstantPoolGen getConstantPool() { + return cp; + } + + + public void setConstantPool( ConstantPoolGen constant_pool ) { + cp = constant_pool; + } + + + public void setClassNameIndex( int class_name_index ) { + this.class_name_index = class_name_index; + class_name = cp.getConstantPool().getConstantString(class_name_index, + Constants.CONSTANT_Class).replace('/', '.'); + } + + + public void setSuperclassNameIndex( int superclass_name_index ) { + this.superclass_name_index = superclass_name_index; + super_class_name = cp.getConstantPool().getConstantString(superclass_name_index, + Constants.CONSTANT_Class).replace('/', '.'); + } + + + public int getSuperclassNameIndex() { + return superclass_name_index; + } + + + public int getClassNameIndex() { + return class_name_index; + } + + private ArrayList observers; + + + /** Add observer for this object. + */ + public void addObserver( ClassObserver o ) { + if (observers == null) { + observers = new ArrayList(); + } + observers.add(o); + } + + + /** Remove observer for this object. + */ + public void removeObserver( ClassObserver o ) { + if (observers != null) { + observers.remove(o); + } + } + + + /** Call notify() method on all observers. This method is not called + * automatically whenever the state has changed, but has to be + * called by the user after he has finished editing the object. + */ + public void update() { + if (observers != null) { + for (Iterator e = observers.iterator(); e.hasNext();) { + ((ClassObserver) e.next()).notify(this); + } + } + } + + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + System.err.println(e); + return null; + } + } + + + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return _cmp; + } + + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator( BCELComparator comparator ) { + _cmp = comparator; + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default two ClassGen objects are said to be equal when + * their class names are equal. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals( Object obj ) { + return _cmp.equals(this, obj); + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default return the hashcode of the class name. + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return _cmp.hashCode(this); + } +} diff --git a/src/org/apache/bcel/generic/ClassGenException.java b/src/org/apache/bcel/generic/ClassGenException.java new file mode 100644 index 0000000..c2d404d --- /dev/null +++ b/src/org/apache/bcel/generic/ClassGenException.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Thrown on internal errors. Extends RuntimeException so it hasn't to be declared + * in the throws clause every time. + * + * @version $Id: ClassGenException.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ClassGenException extends RuntimeException { + + public ClassGenException() { + super(); + } + + + public ClassGenException(String s) { + super(s); + } +} diff --git a/src/org/apache/bcel/generic/ClassObserver.java b/src/org/apache/bcel/generic/ClassObserver.java new file mode 100644 index 0000000..e223d80 --- /dev/null +++ b/src/org/apache/bcel/generic/ClassObserver.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Implement this interface if you're interested in changes to a ClassGen object + * and register yourself with addObserver(). + * + * @version $Id: ClassObserver.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface ClassObserver { + + public void notify( ClassGen clazz ); +} diff --git a/src/org/apache/bcel/generic/CodeExceptionGen.java b/src/org/apache/bcel/generic/CodeExceptionGen.java new file mode 100644 index 0000000..559993a --- /dev/null +++ b/src/org/apache/bcel/generic/CodeExceptionGen.java @@ -0,0 +1,184 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.classfile.CodeException; + +/** + * This class represents an exception handler, i.e., specifies the region where + * a handler is active and an instruction where the actual handling is done. + * pool as parameters. Opposed to the JVM specification the end of the handled + * region is set to be inclusive, i.e. all instructions between start and end + * are protected including the start and end instructions (handles) themselves. + * The end of the region is automatically mapped to be exclusive when calling + * getCodeException(), i.e., there is no difference semantically. + * + * @version $Id: CodeExceptionGen.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see MethodGen + * @see CodeException + * @see InstructionHandle + */ +public final class CodeExceptionGen implements InstructionTargeter, Cloneable, java.io.Serializable { + + private InstructionHandle start_pc; + private InstructionHandle end_pc; + private InstructionHandle handler_pc; + private ObjectType catch_type; + + + /** + * Add an exception handler, i.e., specify region where a handler is active and an + * instruction where the actual handling is done. + * + * @param start_pc Start of handled region (inclusive) + * @param end_pc End of handled region (inclusive) + * @param handler_pc Where handling is done + * @param catch_type which exception is handled, null for ANY + */ + public CodeExceptionGen(InstructionHandle start_pc, InstructionHandle end_pc, + InstructionHandle handler_pc, ObjectType catch_type) { + setStartPC(start_pc); + setEndPC(end_pc); + setHandlerPC(handler_pc); + this.catch_type = catch_type; + } + + + /** + * Get CodeException object.
      + * + * This relies on that the instruction list has already been dumped + * to byte code or or that the `setPositions' methods has been + * called for the instruction list. + * + * @param cp constant pool + */ + public CodeException getCodeException( ConstantPoolGen cp ) { + return new CodeException(start_pc.getPosition(), end_pc.getPosition() + + end_pc.getInstruction().getLength(), handler_pc.getPosition(), + (catch_type == null) ? 0 : cp.addClass(catch_type)); + } + + + /* Set start of handler + * @param start_pc Start of handled region (inclusive) + */ + public void setStartPC( InstructionHandle start_pc ) { + BranchInstruction.notifyTarget(this.start_pc, start_pc, this); + this.start_pc = start_pc; + } + + + /* Set end of handler + * @param end_pc End of handled region (inclusive) + */ + public void setEndPC( InstructionHandle end_pc ) { + BranchInstruction.notifyTarget(this.end_pc, end_pc, this); + this.end_pc = end_pc; + } + + + /* Set handler code + * @param handler_pc Start of handler + */ + public void setHandlerPC( InstructionHandle handler_pc ) { + BranchInstruction.notifyTarget(this.handler_pc, handler_pc, this); + this.handler_pc = handler_pc; + } + + + /** + * @param old_ih old target, either start or end + * @param new_ih new target + */ + public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ) { + boolean targeted = false; + if (start_pc == old_ih) { + targeted = true; + setStartPC(new_ih); + } + if (end_pc == old_ih) { + targeted = true; + setEndPC(new_ih); + } + if (handler_pc == old_ih) { + targeted = true; + setHandlerPC(new_ih); + } + if (!targeted) { + throw new ClassGenException("Not targeting " + old_ih + ", but {" + start_pc + ", " + + end_pc + ", " + handler_pc + "}"); + } + } + + + /** + * @return true, if ih is target of this handler + */ + public boolean containsTarget( InstructionHandle ih ) { + return (start_pc == ih) || (end_pc == ih) || (handler_pc == ih); + } + + + /** Sets the type of the Exception to catch. Set 'null' for ANY. */ + public void setCatchType( ObjectType catch_type ) { + this.catch_type = catch_type; + } + + + /** Gets the type of the Exception to catch, 'null' for ANY. */ + public ObjectType getCatchType() { + return catch_type; + } + + + /** @return start of handled region (inclusive) + */ + public InstructionHandle getStartPC() { + return start_pc; + } + + + /** @return end of handled region (inclusive) + */ + public InstructionHandle getEndPC() { + return end_pc; + } + + + /** @return start of handler + */ + public InstructionHandle getHandlerPC() { + return handler_pc; + } + + + public String toString() { + return "CodeExceptionGen(" + start_pc + ", " + end_pc + ", " + handler_pc + ")"; + } + + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + System.err.println(e); + return null; + } + } +} diff --git a/src/org/apache/bcel/generic/CompoundInstruction.java b/src/org/apache/bcel/generic/CompoundInstruction.java new file mode 100644 index 0000000..0d7eb23 --- /dev/null +++ b/src/org/apache/bcel/generic/CompoundInstruction.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Wrapper class for `compound' operations, virtual instructions that + * don't exist as byte code, but give a useful meaning. For example, + * the (virtual) PUSH instruction takes an arbitray argument and produces the + * appropiate code at dump time (ICONST, LDC, BIPUSH, ...). Also you can use the + * SWITCH instruction as a useful template for either LOOKUPSWITCH or + * TABLESWITCH. + * + * The interface provides the possibilty for the user to write + * `templates' or `macros' for such reuseable code patterns. + * + * @version $Id: CompoundInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see PUSH + * @see SWITCH + */ +public interface CompoundInstruction { + + public InstructionList getInstructionList(); +} diff --git a/src/org/apache/bcel/generic/ConstantPoolGen.java b/src/org/apache/bcel/generic/ConstantPoolGen.java new file mode 100644 index 0000000..581ca59 --- /dev/null +++ b/src/org/apache/bcel/generic/ConstantPoolGen.java @@ -0,0 +1,764 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.util.HashMap; +import java.util.Map; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.classfile.ConstantCP; +import org.apache.bcel.classfile.ConstantClass; +import org.apache.bcel.classfile.ConstantDouble; +import org.apache.bcel.classfile.ConstantFieldref; +import org.apache.bcel.classfile.ConstantFloat; +import org.apache.bcel.classfile.ConstantInteger; +import org.apache.bcel.classfile.ConstantInterfaceMethodref; +import org.apache.bcel.classfile.ConstantLong; +import org.apache.bcel.classfile.ConstantMethodref; +import org.apache.bcel.classfile.ConstantNameAndType; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.ConstantString; +import org.apache.bcel.classfile.ConstantUtf8; + +/** + * This class is used to build up a constant pool. The user adds + * constants via `addXXX' methods, `addString', `addClass', + * etc.. These methods return an index into the constant + * pool. Finally, `getFinalConstantPool()' returns the constant pool + * built up. Intermediate versions of the constant pool can be + * obtained with `getConstantPool()'. A constant pool has capacity for + * Constants.MAX_SHORT entries. Note that the first (0) is used by the + * JVM and that Double and Long constants need two slots. + * + * @version $Id: ConstantPoolGen.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constant + */ +public class ConstantPoolGen implements java.io.Serializable { + + protected int size = 1024; // Inital size, sufficient in most cases + protected Constant[] constants = new Constant[size]; + protected int index = 1; // First entry (0) used by JVM + private static final String METHODREF_DELIM = ":"; + private static final String IMETHODREF_DELIM = "#"; + private static final String FIELDREF_DELIM = "&"; + private static final String NAT_DELIM = "%"; + + private static class Index implements java.io.Serializable { + + int index; + + + Index(int i) { + index = i; + } + } + + + /** + * Initialize with given array of constants. + * + * @param cs array of given constants, new ones will be appended + */ + public ConstantPoolGen(Constant[] cs) { + if (cs.length > size) { + size = cs.length; + constants = new Constant[size]; + } + System.arraycopy(cs, 0, constants, 0, cs.length); + if (cs.length > 0) { + index = cs.length; + } + for (int i = 1; i < index; i++) { + Constant c = constants[i]; + if (c instanceof ConstantString) { + ConstantString s = (ConstantString) c; + ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()]; + String key = u8.getBytes(); + if (!string_table.containsKey(key)) { + string_table.put(key, new Index(i)); + } + } else if (c instanceof ConstantClass) { + ConstantClass s = (ConstantClass) c; + ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()]; + String key = u8.getBytes(); + if (!class_table.containsKey(key)) { + class_table.put(key, new Index(i)); + } + } else if (c instanceof ConstantNameAndType) { + ConstantNameAndType n = (ConstantNameAndType) c; + ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()]; + ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()]; + String key = u8.getBytes() + NAT_DELIM + u8_2.getBytes(); + if (!n_a_t_table.containsKey(key)) { + n_a_t_table.put(key, new Index(i)); + } + } else if (c instanceof ConstantUtf8) { + ConstantUtf8 u = (ConstantUtf8) c; + String key = u.getBytes(); + if (!utf8_table.containsKey(key)) { + utf8_table.put(key, new Index(i)); + } + } else if (c instanceof ConstantCP) { + ConstantCP m = (ConstantCP) c; + ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()]; + ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()]; + ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()]; + String class_name = u8.getBytes().replace('/', '.'); + u8 = (ConstantUtf8) constants[n.getNameIndex()]; + String method_name = u8.getBytes(); + u8 = (ConstantUtf8) constants[n.getSignatureIndex()]; + String signature = u8.getBytes(); + String delim = METHODREF_DELIM; + if (c instanceof ConstantInterfaceMethodref) { + delim = IMETHODREF_DELIM; + } else if (c instanceof ConstantFieldref) { + delim = FIELDREF_DELIM; + } + String key = class_name + delim + method_name + delim + signature; + if (!cp_table.containsKey(key)) { + cp_table.put(key, new Index(i)); + } + } + } + } + + + /** + * Initialize with given constant pool. + */ + public ConstantPoolGen(ConstantPool cp) { + this(cp.getConstantPool()); + } + + + /** + * Create empty constant pool. + */ + public ConstantPoolGen() { + } + + + /** Resize internal array of constants. + */ + protected void adjustSize() { + if (index + 3 >= size) { + Constant[] cs = constants; + size *= 2; + constants = new Constant[size]; + System.arraycopy(cs, 0, constants, 0, index); + } + } + + private Map string_table = new HashMap(); + + + /** + * Look for ConstantString in ConstantPool containing String `str'. + * + * @param str String to search for + * @return index on success, -1 otherwise + */ + public int lookupString( String str ) { + Index index = (Index) string_table.get(str); + return (index != null) ? index.index : -1; + } + + + /** + * Add a new String constant to the ConstantPool, if it is not already in there. + * + * @param str String to add + * @return index of entry + */ + public int addString( String str ) { + int ret; + if ((ret = lookupString(str)) != -1) { + return ret; // Already in CP + } + int utf8 = addUtf8(str); + adjustSize(); + ConstantString s = new ConstantString(utf8); + ret = index; + constants[index++] = s; + if (!string_table.containsKey(str)) { + string_table.put(str, new Index(ret)); + } + return ret; + } + + private Map class_table = new HashMap(); + + + /** + * Look for ConstantClass in ConstantPool named `str'. + * + * @param str String to search for + * @return index on success, -1 otherwise + */ + public int lookupClass( String str ) { + Index index = (Index) class_table.get(str.replace('.', '/')); + return (index != null) ? index.index : -1; + } + + + private int addClass_( String clazz ) { + int ret; + if ((ret = lookupClass(clazz)) != -1) { + return ret; // Already in CP + } + adjustSize(); + ConstantClass c = new ConstantClass(addUtf8(clazz)); + ret = index; + constants[index++] = c; + if (!class_table.containsKey(clazz)) { + class_table.put(clazz, new Index(ret)); + } + return ret; + } + + + /** + * Add a new Class reference to the ConstantPool, if it is not already in there. + * + * @param str Class to add + * @return index of entry + */ + public int addClass( String str ) { + return addClass_(str.replace('.', '/')); + } + + + /** + * Add a new Class reference to the ConstantPool for a given type. + * + * @param type Class to add + * @return index of entry + */ + public int addClass( ObjectType type ) { + return addClass(type.getClassName()); + } + + + /** + * Add a reference to an array class (e.g. String[][]) as needed by MULTIANEWARRAY + * instruction, e.g. to the ConstantPool. + * + * @param type type of array class + * @return index of entry + */ + public int addArrayClass( ArrayType type ) { + return addClass_(type.getSignature()); + } + + + /** + * Look for ConstantInteger in ConstantPool. + * + * @param n integer number to look for + * @return index on success, -1 otherwise + */ + public int lookupInteger( int n ) { + for (int i = 1; i < index; i++) { + if (constants[i] instanceof ConstantInteger) { + ConstantInteger c = (ConstantInteger) constants[i]; + if (c.getBytes() == n) { + return i; + } + } + } + return -1; + } + + + /** + * Add a new Integer constant to the ConstantPool, if it is not already in there. + * + * @param n integer number to add + * @return index of entry + */ + public int addInteger( int n ) { + int ret; + if ((ret = lookupInteger(n)) != -1) { + return ret; // Already in CP + } + adjustSize(); + ret = index; + constants[index++] = new ConstantInteger(n); + return ret; + } + + + /** + * Look for ConstantFloat in ConstantPool. + * + * @param n Float number to look for + * @return index on success, -1 otherwise + */ + public int lookupFloat( float n ) { + int bits = Float.floatToIntBits(n); + for (int i = 1; i < index; i++) { + if (constants[i] instanceof ConstantFloat) { + ConstantFloat c = (ConstantFloat) constants[i]; + if (Float.floatToIntBits(c.getBytes()) == bits) { + return i; + } + } + } + return -1; + } + + + /** + * Add a new Float constant to the ConstantPool, if it is not already in there. + * + * @param n Float number to add + * @return index of entry + */ + public int addFloat( float n ) { + int ret; + if ((ret = lookupFloat(n)) != -1) { + return ret; // Already in CP + } + adjustSize(); + ret = index; + constants[index++] = new ConstantFloat(n); + return ret; + } + + private Map utf8_table = new HashMap(); + + + /** + * Look for ConstantUtf8 in ConstantPool. + * + * @param n Utf8 string to look for + * @return index on success, -1 otherwise + */ + public int lookupUtf8( String n ) { + Index index = (Index) utf8_table.get(n); + return (index != null) ? index.index : -1; + } + + + /** + * Add a new Utf8 constant to the ConstantPool, if it is not already in there. + * + * @param n Utf8 string to add + * @return index of entry + */ + public int addUtf8( String n ) { + int ret; + if ((ret = lookupUtf8(n)) != -1) { + return ret; // Already in CP + } + adjustSize(); + ret = index; + constants[index++] = new ConstantUtf8(n); + if (!utf8_table.containsKey(n)) { + utf8_table.put(n, new Index(ret)); + } + return ret; + } + + + /** + * Look for ConstantLong in ConstantPool. + * + * @param n Long number to look for + * @return index on success, -1 otherwise + */ + public int lookupLong( long n ) { + for (int i = 1; i < index; i++) { + if (constants[i] instanceof ConstantLong) { + ConstantLong c = (ConstantLong) constants[i]; + if (c.getBytes() == n) { + return i; + } + } + } + return -1; + } + + + /** + * Add a new long constant to the ConstantPool, if it is not already in there. + * + * @param n Long number to add + * @return index of entry + */ + public int addLong( long n ) { + int ret; + if ((ret = lookupLong(n)) != -1) { + return ret; // Already in CP + } + adjustSize(); + ret = index; + constants[index] = new ConstantLong(n); + index += 2; // Wastes one entry according to spec + return ret; + } + + + /** + * Look for ConstantDouble in ConstantPool. + * + * @param n Double number to look for + * @return index on success, -1 otherwise + */ + public int lookupDouble( double n ) { + long bits = Double.doubleToLongBits(n); + for (int i = 1; i < index; i++) { + if (constants[i] instanceof ConstantDouble) { + ConstantDouble c = (ConstantDouble) constants[i]; + if (Double.doubleToLongBits(c.getBytes()) == bits) { + return i; + } + } + } + return -1; + } + + + /** + * Add a new double constant to the ConstantPool, if it is not already in there. + * + * @param n Double number to add + * @return index of entry + */ + public int addDouble( double n ) { + int ret; + if ((ret = lookupDouble(n)) != -1) { + return ret; // Already in CP + } + adjustSize(); + ret = index; + constants[index] = new ConstantDouble(n); + index += 2; // Wastes one entry according to spec + return ret; + } + + private Map n_a_t_table = new HashMap(); + + + /** + * Look for ConstantNameAndType in ConstantPool. + * + * @param name of variable/method + * @param signature of variable/method + * @return index on success, -1 otherwise + */ + public int lookupNameAndType( String name, String signature ) { + Index _index = (Index) n_a_t_table.get(name + NAT_DELIM + signature); + return (_index != null) ? _index.index : -1; + } + + + /** + * Add a new NameAndType constant to the ConstantPool if it is not already + * in there. + * + * @param name Name string to add + * @param signature signature string to add + * @return index of entry + */ + public int addNameAndType( String name, String signature ) { + int ret; + int name_index, signature_index; + if ((ret = lookupNameAndType(name, signature)) != -1) { + return ret; // Already in CP + } + adjustSize(); + name_index = addUtf8(name); + signature_index = addUtf8(signature); + ret = index; + constants[index++] = new ConstantNameAndType(name_index, signature_index); + String key = name + NAT_DELIM + signature; + if (!n_a_t_table.containsKey(key)) { + n_a_t_table.put(key, new Index(ret)); + } + return ret; + } + + private Map cp_table = new HashMap(); + + + /** + * Look for ConstantMethodref in ConstantPool. + * + * @param class_name Where to find method + * @param method_name Guess what + * @param signature return and argument types + * @return index on success, -1 otherwise + */ + public int lookupMethodref( String class_name, String method_name, String signature ) { + Index index = (Index) cp_table.get(class_name + METHODREF_DELIM + method_name + + METHODREF_DELIM + signature); + return (index != null) ? index.index : -1; + } + + + public int lookupMethodref( MethodGen method ) { + return lookupMethodref(method.getClassName(), method.getName(), method.getSignature()); + } + + + /** + * Add a new Methodref constant to the ConstantPool, if it is not already + * in there. + * + * @param class_name class name string to add + * @param method_name method name string to add + * @param signature method signature string to add + * @return index of entry + */ + public int addMethodref( String class_name, String method_name, String signature ) { + int ret, class_index, name_and_type_index; + if ((ret = lookupMethodref(class_name, method_name, signature)) != -1) { + return ret; // Already in CP + } + adjustSize(); + name_and_type_index = addNameAndType(method_name, signature); + class_index = addClass(class_name); + ret = index; + constants[index++] = new ConstantMethodref(class_index, name_and_type_index); + String key = class_name + METHODREF_DELIM + method_name + METHODREF_DELIM + signature; + if (!cp_table.containsKey(key)) { + cp_table.put(key, new Index(ret)); + } + return ret; + } + + + public int addMethodref( MethodGen method ) { + return addMethodref(method.getClassName(), method.getName(), method.getSignature()); + } + + + /** + * Look for ConstantInterfaceMethodref in ConstantPool. + * + * @param class_name Where to find method + * @param method_name Guess what + * @param signature return and argument types + * @return index on success, -1 otherwise + */ + public int lookupInterfaceMethodref( String class_name, String method_name, String signature ) { + Index index = (Index) cp_table.get(class_name + IMETHODREF_DELIM + method_name + + IMETHODREF_DELIM + signature); + return (index != null) ? index.index : -1; + } + + + public int lookupInterfaceMethodref( MethodGen method ) { + return lookupInterfaceMethodref(method.getClassName(), method.getName(), method + .getSignature()); + } + + + /** + * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already + * in there. + * + * @param class_name class name string to add + * @param method_name method name string to add + * @param signature signature string to add + * @return index of entry + */ + public int addInterfaceMethodref( String class_name, String method_name, String signature ) { + int ret, class_index, name_and_type_index; + if ((ret = lookupInterfaceMethodref(class_name, method_name, signature)) != -1) { + return ret; // Already in CP + } + adjustSize(); + class_index = addClass(class_name); + name_and_type_index = addNameAndType(method_name, signature); + ret = index; + constants[index++] = new ConstantInterfaceMethodref(class_index, name_and_type_index); + String key = class_name + IMETHODREF_DELIM + method_name + IMETHODREF_DELIM + signature; + if (!cp_table.containsKey(key)) { + cp_table.put(key, new Index(ret)); + } + return ret; + } + + + public int addInterfaceMethodref( MethodGen method ) { + return addInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature()); + } + + + /** + * Look for ConstantFieldref in ConstantPool. + * + * @param class_name Where to find method + * @param field_name Guess what + * @param signature return and argument types + * @return index on success, -1 otherwise + */ + public int lookupFieldref( String class_name, String field_name, String signature ) { + Index index = (Index) cp_table.get(class_name + FIELDREF_DELIM + field_name + + FIELDREF_DELIM + signature); + return (index != null) ? index.index : -1; + } + + + /** + * Add a new Fieldref constant to the ConstantPool, if it is not already + * in there. + * + * @param class_name class name string to add + * @param field_name field name string to add + * @param signature signature string to add + * @return index of entry + */ + public int addFieldref( String class_name, String field_name, String signature ) { + int ret; + int class_index, name_and_type_index; + if ((ret = lookupFieldref(class_name, field_name, signature)) != -1) { + return ret; // Already in CP + } + adjustSize(); + class_index = addClass(class_name); + name_and_type_index = addNameAndType(field_name, signature); + ret = index; + constants[index++] = new ConstantFieldref(class_index, name_and_type_index); + String key = class_name + FIELDREF_DELIM + field_name + FIELDREF_DELIM + signature; + if (!cp_table.containsKey(key)) { + cp_table.put(key, new Index(ret)); + } + return ret; + } + + + /** + * @param i index in constant pool + * @return constant pool entry at index i + */ + public Constant getConstant( int i ) { + return constants[i]; + } + + + /** + * Use with care! + * + * @param i index in constant pool + * @param c new constant pool entry at index i + */ + public void setConstant( int i, Constant c ) { + constants[i] = c; + } + + + /** + * @return intermediate constant pool + */ + public ConstantPool getConstantPool() { + return new ConstantPool(constants); + } + + + /** + * @return current size of constant pool + */ + public int getSize() { + return index; + } + + + /** + * @return constant pool with proper length + */ + public ConstantPool getFinalConstantPool() { + Constant[] cs = new Constant[index]; + System.arraycopy(constants, 0, cs, 0, index); + return new ConstantPool(cs); + } + + + /** + * @return String representation. + */ + public String toString() { + StringBuffer buf = new StringBuffer(); + for (int i = 1; i < index; i++) { + buf.append(i).append(")").append(constants[i]).append("\n"); + } + return buf.toString(); + } + + + /** Import constant from another ConstantPool and return new index. + */ + public int addConstant( Constant c, ConstantPoolGen cp ) { + Constant[] constants = cp.getConstantPool().getConstantPool(); + switch (c.getTag()) { + case Constants.CONSTANT_String: { + ConstantString s = (ConstantString) c; + ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()]; + return addString(u8.getBytes()); + } + case Constants.CONSTANT_Class: { + ConstantClass s = (ConstantClass) c; + ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()]; + return addClass(u8.getBytes()); + } + case Constants.CONSTANT_NameAndType: { + ConstantNameAndType n = (ConstantNameAndType) c; + ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()]; + ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()]; + return addNameAndType(u8.getBytes(), u8_2.getBytes()); + } + case Constants.CONSTANT_Utf8: + return addUtf8(((ConstantUtf8) c).getBytes()); + case Constants.CONSTANT_Double: + return addDouble(((ConstantDouble) c).getBytes()); + case Constants.CONSTANT_Float: + return addFloat(((ConstantFloat) c).getBytes()); + case Constants.CONSTANT_Long: + return addLong(((ConstantLong) c).getBytes()); + case Constants.CONSTANT_Integer: + return addInteger(((ConstantInteger) c).getBytes()); + case Constants.CONSTANT_InterfaceMethodref: + case Constants.CONSTANT_Methodref: + case Constants.CONSTANT_Fieldref: { + ConstantCP m = (ConstantCP) c; + ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()]; + ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()]; + ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()]; + String class_name = u8.getBytes().replace('/', '.'); + u8 = (ConstantUtf8) constants[n.getNameIndex()]; + String name = u8.getBytes(); + u8 = (ConstantUtf8) constants[n.getSignatureIndex()]; + String signature = u8.getBytes(); + switch (c.getTag()) { + case Constants.CONSTANT_InterfaceMethodref: + return addInterfaceMethodref(class_name, name, signature); + case Constants.CONSTANT_Methodref: + return addMethodref(class_name, name, signature); + case Constants.CONSTANT_Fieldref: + return addFieldref(class_name, name, signature); + default: // Never reached + throw new RuntimeException("Unknown constant type " + c); + } + } + default: // Never reached + throw new RuntimeException("Unknown constant type " + c); + } + } +} diff --git a/src/org/apache/bcel/generic/ConstantPushInstruction.java b/src/org/apache/bcel/generic/ConstantPushInstruction.java new file mode 100644 index 0000000..2c69228 --- /dev/null +++ b/src/org/apache/bcel/generic/ConstantPushInstruction.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denotes a push instruction that produces a literal on the stack + * such as SIPUSH, BIPUSH, ICONST, etc. + * + * @version $Id: ConstantPushInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + + * @see ICONST + * @see SIPUSH + */ +public interface ConstantPushInstruction extends PushInstruction, TypedInstruction { + + public Number getValue(); +} diff --git a/src/org/apache/bcel/generic/ConversionInstruction.java b/src/org/apache/bcel/generic/ConversionInstruction.java new file mode 100644 index 0000000..accb79c --- /dev/null +++ b/src/org/apache/bcel/generic/ConversionInstruction.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; + +/** + * Super class for the x2y family of instructions. + * + * @version $Id: ConversionInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class ConversionInstruction extends Instruction implements TypedInstruction, + StackProducer, StackConsumer { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + ConversionInstruction() { + } + + + /** + * @param opcode opcode of instruction + */ + protected ConversionInstruction(short opcode) { + super(opcode, (short) 1); + } + + + /** @return type associated with the instruction + */ + public Type getType( ConstantPoolGen cp ) { + switch (opcode) { + case Constants.D2I: + case Constants.F2I: + case Constants.L2I: + return Type.INT; + case Constants.D2F: + case Constants.I2F: + case Constants.L2F: + return Type.FLOAT; + case Constants.D2L: + case Constants.F2L: + case Constants.I2L: + return Type.LONG; + case Constants.F2D: + case Constants.I2D: + case Constants.L2D: + return Type.DOUBLE; + case Constants.I2B: + return Type.BYTE; + case Constants.I2C: + return Type.CHAR; + case Constants.I2S: + return Type.SHORT; + default: // Never reached + throw new ClassGenException("Unknown type " + opcode); + } + } +} diff --git a/src/org/apache/bcel/generic/D2F.java b/src/org/apache/bcel/generic/D2F.java new file mode 100644 index 0000000..1990492 --- /dev/null +++ b/src/org/apache/bcel/generic/D2F.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * D2F - Convert double to float + *
      Stack: ..., value.word1, value.word2 -> ..., result
      + * + * @version $Id: D2F.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class D2F extends ConversionInstruction { + + /** Convert double to float + */ + public D2F() { + super(org.apache.bcel.Constants.D2F); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitD2F(this); + } +} diff --git a/src/org/apache/bcel/generic/D2I.java b/src/org/apache/bcel/generic/D2I.java new file mode 100644 index 0000000..cca2f9f --- /dev/null +++ b/src/org/apache/bcel/generic/D2I.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * D2I - Convert double to int + *
      Stack: ..., value.word1, value.word2 -> ..., result
      + * + * @version $Id: D2I.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class D2I extends ConversionInstruction { + + /** Convert double to int + */ + public D2I() { + super(org.apache.bcel.Constants.D2I); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitD2I(this); + } +} diff --git a/src/org/apache/bcel/generic/D2L.java b/src/org/apache/bcel/generic/D2L.java new file mode 100644 index 0000000..0f63663 --- /dev/null +++ b/src/org/apache/bcel/generic/D2L.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * D2L - Convert double to long + *
      Stack: ..., value.word1, value.word2 -> ..., result.word1, result.word2
      + * + * @version $Id: D2L.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class D2L extends ConversionInstruction { + + /** Convert double to long + */ + public D2L() { + super(org.apache.bcel.Constants.D2L); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitD2L(this); + } +} diff --git a/src/org/apache/bcel/generic/DADD.java b/src/org/apache/bcel/generic/DADD.java new file mode 100644 index 0000000..7918b47 --- /dev/null +++ b/src/org/apache/bcel/generic/DADD.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DADD - Add doubles + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result.word1, result1.word2 + * + * @version $Id: DADD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DADD extends ArithmeticInstruction { + + /** Add doubles + */ + public DADD() { + super(org.apache.bcel.Constants.DADD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitDADD(this); + } +} diff --git a/src/org/apache/bcel/generic/DALOAD.java b/src/org/apache/bcel/generic/DALOAD.java new file mode 100644 index 0000000..de2def0 --- /dev/null +++ b/src/org/apache/bcel/generic/DALOAD.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DALOAD - Load double from array + *
      Stack: ..., arrayref, index -> ..., result.word1, result.word2
      + * + * @version $Id: DALOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DALOAD extends ArrayInstruction implements StackProducer { + + /** Load double from array + */ + public DALOAD() { + super(org.apache.bcel.Constants.DALOAD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitDALOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/DASTORE.java b/src/org/apache/bcel/generic/DASTORE.java new file mode 100644 index 0000000..5de71bc --- /dev/null +++ b/src/org/apache/bcel/generic/DASTORE.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DASTORE - Store into double array + *
      Stack: ..., arrayref, index, value.word1, value.word2 -> ...
      + * + * @version $Id: DASTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DASTORE extends ArrayInstruction implements StackConsumer { + + /** Store double into array + */ + public DASTORE() { + super(org.apache.bcel.Constants.DASTORE); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitDASTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/DCMPG.java b/src/org/apache/bcel/generic/DCMPG.java new file mode 100644 index 0000000..7190b82 --- /dev/null +++ b/src/org/apache/bcel/generic/DCMPG.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DCMPG - Compare doubles: value1 > value2 + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result + * + * @version $Id: DCMPG.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DCMPG extends Instruction implements TypedInstruction, StackProducer, StackConsumer { + + public DCMPG() { + super(org.apache.bcel.Constants.DCMPG, (short) 1); + } + + + /** @return Type.DOUBLE + */ + public Type getType( ConstantPoolGen cp ) { + return Type.DOUBLE; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitDCMPG(this); + } +} diff --git a/src/org/apache/bcel/generic/DCMPL.java b/src/org/apache/bcel/generic/DCMPL.java new file mode 100644 index 0000000..9dcfc4f --- /dev/null +++ b/src/org/apache/bcel/generic/DCMPL.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DCMPL - Compare doubles: value1 < value2 + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result + * + * @version $Id: DCMPL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DCMPL extends Instruction implements TypedInstruction, StackProducer, StackConsumer { + + public DCMPL() { + super(org.apache.bcel.Constants.DCMPL, (short) 1); + } + + + /** @return Type.DOUBLE + */ + public Type getType( ConstantPoolGen cp ) { + return Type.DOUBLE; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitDCMPL(this); + } +} diff --git a/src/org/apache/bcel/generic/DCONST.java b/src/org/apache/bcel/generic/DCONST.java new file mode 100644 index 0000000..5af8686 --- /dev/null +++ b/src/org/apache/bcel/generic/DCONST.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DCONST - Push 0.0 or 1.0, other values cause an exception + * + *
      Stack: ... -> ..., 
      + * + * @version $Id: DCONST.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DCONST extends Instruction implements ConstantPushInstruction, TypedInstruction { + + private double value; + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + DCONST() { + } + + + public DCONST(double f) { + super(org.apache.bcel.Constants.DCONST_0, (short) 1); + if (f == 0.0) { + opcode = org.apache.bcel.Constants.DCONST_0; + } else if (f == 1.0) { + opcode = org.apache.bcel.Constants.DCONST_1; + } else { + throw new ClassGenException("DCONST can be used only for 0.0 and 1.0: " + f); + } + value = f; + } + + + public Number getValue() { + return new Double(value); + } + + + /** @return Type.DOUBLE + */ + public Type getType( ConstantPoolGen cp ) { + return Type.DOUBLE; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitPushInstruction(this); + v.visitStackProducer(this); + v.visitTypedInstruction(this); + v.visitConstantPushInstruction(this); + v.visitDCONST(this); + } +} diff --git a/src/org/apache/bcel/generic/DDIV.java b/src/org/apache/bcel/generic/DDIV.java new file mode 100644 index 0000000..44c2308 --- /dev/null +++ b/src/org/apache/bcel/generic/DDIV.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DDIV - Divide doubles + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result.word1, result.word2 + * + * @version $Id: DDIV.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DDIV extends ArithmeticInstruction { + + /** Divide doubles + */ + public DDIV() { + super(org.apache.bcel.Constants.DDIV); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitDDIV(this); + } +} diff --git a/src/org/apache/bcel/generic/DLOAD.java b/src/org/apache/bcel/generic/DLOAD.java new file mode 100644 index 0000000..360d23b --- /dev/null +++ b/src/org/apache/bcel/generic/DLOAD.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DLOAD - Load double from local variable + *
      Stack ... -> ..., result.word1, result.word2
      + * + * @version $Id: DLOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DLOAD extends LoadInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + DLOAD() { + super(org.apache.bcel.Constants.DLOAD, org.apache.bcel.Constants.DLOAD_0); + } + + + /** Load double from local variable + * @param n index of local variable + */ + public DLOAD(int n) { + super(org.apache.bcel.Constants.DLOAD, org.apache.bcel.Constants.DLOAD_0, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + super.accept(v); + v.visitDLOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/DMUL.java b/src/org/apache/bcel/generic/DMUL.java new file mode 100644 index 0000000..79e64ae --- /dev/null +++ b/src/org/apache/bcel/generic/DMUL.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DMUL - Multiply doubles + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result.word1, result.word2 + * + * @version $Id: DMUL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DMUL extends ArithmeticInstruction { + + /** Multiply doubles + */ + public DMUL() { + super(org.apache.bcel.Constants.DMUL); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitDMUL(this); + } +} diff --git a/src/org/apache/bcel/generic/DNEG.java b/src/org/apache/bcel/generic/DNEG.java new file mode 100644 index 0000000..c7e2d21 --- /dev/null +++ b/src/org/apache/bcel/generic/DNEG.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DNEG - Negate double + *
      Stack: ..., value.word1, value.word2 -> ..., result.word1, result.word2
      + * + * @version $Id: DNEG.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DNEG extends ArithmeticInstruction { + + public DNEG() { + super(org.apache.bcel.Constants.DNEG); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitDNEG(this); + } +} diff --git a/src/org/apache/bcel/generic/DREM.java b/src/org/apache/bcel/generic/DREM.java new file mode 100644 index 0000000..01dfc15 --- /dev/null +++ b/src/org/apache/bcel/generic/DREM.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DREM - Remainder of doubles + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result.word1, result.word2 + * + * @version $Id: DREM.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DREM extends ArithmeticInstruction { + + /** Remainder of doubles + */ + public DREM() { + super(org.apache.bcel.Constants.DREM); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitDREM(this); + } +} diff --git a/src/org/apache/bcel/generic/DRETURN.java b/src/org/apache/bcel/generic/DRETURN.java new file mode 100644 index 0000000..a1ccc8b --- /dev/null +++ b/src/org/apache/bcel/generic/DRETURN.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DRETURN - Return double from method + *
      Stack: ..., value.word1, value.word2 -> <empty>
      + * + * @version $Id: DRETURN.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DRETURN extends ReturnInstruction { + + /** Return double from method + */ + public DRETURN() { + super(org.apache.bcel.Constants.DRETURN); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitReturnInstruction(this); + v.visitDRETURN(this); + } +} diff --git a/src/org/apache/bcel/generic/DSTORE.java b/src/org/apache/bcel/generic/DSTORE.java new file mode 100644 index 0000000..9efeb3f --- /dev/null +++ b/src/org/apache/bcel/generic/DSTORE.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DSTORE - Store double into local variable + *
      Stack: ..., value.word1, value.word2 -> ... 
      + * + * @version $Id: DSTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DSTORE extends StoreInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + DSTORE() { + super(org.apache.bcel.Constants.DSTORE, org.apache.bcel.Constants.DSTORE_0); + } + + + /** Store double into local variable + * @param n index of local variable + */ + public DSTORE(int n) { + super(org.apache.bcel.Constants.DSTORE, org.apache.bcel.Constants.DSTORE_0, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + super.accept(v); + v.visitDSTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/DSUB.java b/src/org/apache/bcel/generic/DSUB.java new file mode 100644 index 0000000..6169cfe --- /dev/null +++ b/src/org/apache/bcel/generic/DSUB.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DSUB - Substract doubles + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result.word1, result.word2 + * + * @version $Id: DSUB.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DSUB extends ArithmeticInstruction { + + /** Substract doubles + */ + public DSUB() { + super(org.apache.bcel.Constants.DSUB); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitDSUB(this); + } +} diff --git a/src/org/apache/bcel/generic/DUP.java b/src/org/apache/bcel/generic/DUP.java new file mode 100644 index 0000000..5900ddf --- /dev/null +++ b/src/org/apache/bcel/generic/DUP.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DUP - Duplicate top operand stack word + *
      Stack: ..., word -> ..., word, word
      + * + * @version $Id: DUP.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DUP extends StackInstruction implements PushInstruction { + + public DUP() { + super(org.apache.bcel.Constants.DUP); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitPushInstruction(this); + v.visitStackInstruction(this); + v.visitDUP(this); + } +} diff --git a/src/org/apache/bcel/generic/DUP2.java b/src/org/apache/bcel/generic/DUP2.java new file mode 100644 index 0000000..688a33b --- /dev/null +++ b/src/org/apache/bcel/generic/DUP2.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DUP2 - Duplicate two top operand stack words + *
      Stack: ..., word2, word1 -> ..., word2, word1, word2, word1
      + * + * @version $Id: DUP2.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DUP2 extends StackInstruction implements PushInstruction { + + public DUP2() { + super(org.apache.bcel.Constants.DUP2); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitPushInstruction(this); + v.visitStackInstruction(this); + v.visitDUP2(this); + } +} diff --git a/src/org/apache/bcel/generic/DUP2_X1.java b/src/org/apache/bcel/generic/DUP2_X1.java new file mode 100644 index 0000000..b522b1a --- /dev/null +++ b/src/org/apache/bcel/generic/DUP2_X1.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DUP2_X1 - Duplicate two top operand stack words and put three down + *
      Stack: ..., word3, word2, word1 -> ..., word2, word1, word3, word2, word1
      + * + * @version $Id: DUP2_X1.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DUP2_X1 extends StackInstruction { + + public DUP2_X1() { + super(org.apache.bcel.Constants.DUP2_X1); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackInstruction(this); + v.visitDUP2_X1(this); + } +} diff --git a/src/org/apache/bcel/generic/DUP2_X2.java b/src/org/apache/bcel/generic/DUP2_X2.java new file mode 100644 index 0000000..8cf009e --- /dev/null +++ b/src/org/apache/bcel/generic/DUP2_X2.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DUP2_X2 - Duplicate two top operand stack words and put four down + *
      Stack: ..., word4, word3, word2, word1 -> ..., word2, word1, word4, word3, word2, word1
      + * + * @version $Id: DUP2_X2.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DUP2_X2 extends StackInstruction { + + public DUP2_X2() { + super(org.apache.bcel.Constants.DUP2_X2); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackInstruction(this); + v.visitDUP2_X2(this); + } +} diff --git a/src/org/apache/bcel/generic/DUP_X1.java b/src/org/apache/bcel/generic/DUP_X1.java new file mode 100644 index 0000000..a672e29 --- /dev/null +++ b/src/org/apache/bcel/generic/DUP_X1.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DUP_X1 - Duplicate top operand stack word and put two down + *
      Stack: ..., word2, word1 -> ..., word1, word2, word1
      + * + * @version $Id: DUP_X1.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DUP_X1 extends StackInstruction { + + public DUP_X1() { + super(org.apache.bcel.Constants.DUP_X1); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackInstruction(this); + v.visitDUP_X1(this); + } +} diff --git a/src/org/apache/bcel/generic/DUP_X2.java b/src/org/apache/bcel/generic/DUP_X2.java new file mode 100644 index 0000000..475c4c8 --- /dev/null +++ b/src/org/apache/bcel/generic/DUP_X2.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * DUP_X2 - Duplicate top operand stack word and put three down + *
      Stack: ..., word3, word2, word1 -> ..., word1, word3, word2, word1
      + * + * @version $Id: DUP_X2.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class DUP_X2 extends StackInstruction { + + public DUP_X2() { + super(org.apache.bcel.Constants.DUP_X2); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackInstruction(this); + v.visitDUP_X2(this); + } +} diff --git a/src/org/apache/bcel/generic/EmptyVisitor.java b/src/org/apache/bcel/generic/EmptyVisitor.java new file mode 100644 index 0000000..b28fecd --- /dev/null +++ b/src/org/apache/bcel/generic/EmptyVisitor.java @@ -0,0 +1,745 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Supplies empty method bodies to be overridden by subclasses. + * + * @version $Id: EmptyVisitor.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class EmptyVisitor implements Visitor { + + public void visitStackInstruction( StackInstruction obj ) { + } + + + public void visitLocalVariableInstruction( LocalVariableInstruction obj ) { + } + + + public void visitBranchInstruction( BranchInstruction obj ) { + } + + + public void visitLoadClass( LoadClass obj ) { + } + + + public void visitFieldInstruction( FieldInstruction obj ) { + } + + + public void visitIfInstruction( IfInstruction obj ) { + } + + + public void visitConversionInstruction( ConversionInstruction obj ) { + } + + + public void visitPopInstruction( PopInstruction obj ) { + } + + + public void visitJsrInstruction( JsrInstruction obj ) { + } + + + public void visitGotoInstruction( GotoInstruction obj ) { + } + + + public void visitStoreInstruction( StoreInstruction obj ) { + } + + + public void visitTypedInstruction( TypedInstruction obj ) { + } + + + public void visitSelect( Select obj ) { + } + + + public void visitUnconditionalBranch( UnconditionalBranch obj ) { + } + + + public void visitPushInstruction( PushInstruction obj ) { + } + + + public void visitArithmeticInstruction( ArithmeticInstruction obj ) { + } + + + public void visitCPInstruction( CPInstruction obj ) { + } + + + public void visitInvokeInstruction( InvokeInstruction obj ) { + } + + + public void visitArrayInstruction( ArrayInstruction obj ) { + } + + + public void visitAllocationInstruction( AllocationInstruction obj ) { + } + + + public void visitReturnInstruction( ReturnInstruction obj ) { + } + + + public void visitFieldOrMethod( FieldOrMethod obj ) { + } + + + public void visitConstantPushInstruction( ConstantPushInstruction obj ) { + } + + + public void visitExceptionThrower( ExceptionThrower obj ) { + } + + + public void visitLoadInstruction( LoadInstruction obj ) { + } + + + public void visitVariableLengthInstruction( VariableLengthInstruction obj ) { + } + + + public void visitStackProducer( StackProducer obj ) { + } + + + public void visitStackConsumer( StackConsumer obj ) { + } + + + public void visitACONST_NULL( ACONST_NULL obj ) { + } + + + public void visitGETSTATIC( GETSTATIC obj ) { + } + + + public void visitIF_ICMPLT( IF_ICMPLT obj ) { + } + + + public void visitMONITOREXIT( MONITOREXIT obj ) { + } + + + public void visitIFLT( IFLT obj ) { + } + + + public void visitLSTORE( LSTORE obj ) { + } + + + public void visitPOP2( POP2 obj ) { + } + + + public void visitBASTORE( BASTORE obj ) { + } + + + public void visitISTORE( ISTORE obj ) { + } + + + public void visitCHECKCAST( CHECKCAST obj ) { + } + + + public void visitFCMPG( FCMPG obj ) { + } + + + public void visitI2F( I2F obj ) { + } + + + public void visitATHROW( ATHROW obj ) { + } + + + public void visitDCMPL( DCMPL obj ) { + } + + + public void visitARRAYLENGTH( ARRAYLENGTH obj ) { + } + + + public void visitDUP( DUP obj ) { + } + + + public void visitINVOKESTATIC( INVOKESTATIC obj ) { + } + + + public void visitLCONST( LCONST obj ) { + } + + + public void visitDREM( DREM obj ) { + } + + + public void visitIFGE( IFGE obj ) { + } + + + public void visitCALOAD( CALOAD obj ) { + } + + + public void visitLASTORE( LASTORE obj ) { + } + + + public void visitI2D( I2D obj ) { + } + + + public void visitDADD( DADD obj ) { + } + + + public void visitINVOKESPECIAL( INVOKESPECIAL obj ) { + } + + + public void visitIAND( IAND obj ) { + } + + + public void visitPUTFIELD( PUTFIELD obj ) { + } + + + public void visitILOAD( ILOAD obj ) { + } + + + public void visitDLOAD( DLOAD obj ) { + } + + + public void visitDCONST( DCONST obj ) { + } + + + public void visitNEW( NEW obj ) { + } + + + public void visitIFNULL( IFNULL obj ) { + } + + + public void visitLSUB( LSUB obj ) { + } + + + public void visitL2I( L2I obj ) { + } + + + public void visitISHR( ISHR obj ) { + } + + + public void visitTABLESWITCH( TABLESWITCH obj ) { + } + + + public void visitIINC( IINC obj ) { + } + + + public void visitDRETURN( DRETURN obj ) { + } + + + public void visitFSTORE( FSTORE obj ) { + } + + + public void visitDASTORE( DASTORE obj ) { + } + + + public void visitIALOAD( IALOAD obj ) { + } + + + public void visitDDIV( DDIV obj ) { + } + + + public void visitIF_ICMPGE( IF_ICMPGE obj ) { + } + + + public void visitLAND( LAND obj ) { + } + + + public void visitIDIV( IDIV obj ) { + } + + + public void visitLOR( LOR obj ) { + } + + + public void visitCASTORE( CASTORE obj ) { + } + + + public void visitFREM( FREM obj ) { + } + + + public void visitLDC( LDC obj ) { + } + + + public void visitBIPUSH( BIPUSH obj ) { + } + + + public void visitDSTORE( DSTORE obj ) { + } + + + public void visitF2L( F2L obj ) { + } + + + public void visitFMUL( FMUL obj ) { + } + + + public void visitLLOAD( LLOAD obj ) { + } + + + public void visitJSR( JSR obj ) { + } + + + public void visitFSUB( FSUB obj ) { + } + + + public void visitSASTORE( SASTORE obj ) { + } + + + public void visitALOAD( ALOAD obj ) { + } + + + public void visitDUP2_X2( DUP2_X2 obj ) { + } + + + public void visitRETURN( RETURN obj ) { + } + + + public void visitDALOAD( DALOAD obj ) { + } + + + public void visitSIPUSH( SIPUSH obj ) { + } + + + public void visitDSUB( DSUB obj ) { + } + + + public void visitL2F( L2F obj ) { + } + + + public void visitIF_ICMPGT( IF_ICMPGT obj ) { + } + + + public void visitF2D( F2D obj ) { + } + + + public void visitI2L( I2L obj ) { + } + + + public void visitIF_ACMPNE( IF_ACMPNE obj ) { + } + + + public void visitPOP( POP obj ) { + } + + + public void visitI2S( I2S obj ) { + } + + + public void visitIFEQ( IFEQ obj ) { + } + + + public void visitSWAP( SWAP obj ) { + } + + + public void visitIOR( IOR obj ) { + } + + + public void visitIREM( IREM obj ) { + } + + + public void visitIASTORE( IASTORE obj ) { + } + + + public void visitNEWARRAY( NEWARRAY obj ) { + } + + + public void visitINVOKEINTERFACE( INVOKEINTERFACE obj ) { + } + + + public void visitINEG( INEG obj ) { + } + + + public void visitLCMP( LCMP obj ) { + } + + + public void visitJSR_W( JSR_W obj ) { + } + + + public void visitMULTIANEWARRAY( MULTIANEWARRAY obj ) { + } + + + public void visitDUP_X2( DUP_X2 obj ) { + } + + + public void visitSALOAD( SALOAD obj ) { + } + + + public void visitIFNONNULL( IFNONNULL obj ) { + } + + + public void visitDMUL( DMUL obj ) { + } + + + public void visitIFNE( IFNE obj ) { + } + + + public void visitIF_ICMPLE( IF_ICMPLE obj ) { + } + + + public void visitLDC2_W( LDC2_W obj ) { + } + + + public void visitGETFIELD( GETFIELD obj ) { + } + + + public void visitLADD( LADD obj ) { + } + + + public void visitNOP( NOP obj ) { + } + + + public void visitFALOAD( FALOAD obj ) { + } + + + public void visitINSTANCEOF( INSTANCEOF obj ) { + } + + + public void visitIFLE( IFLE obj ) { + } + + + public void visitLXOR( LXOR obj ) { + } + + + public void visitLRETURN( LRETURN obj ) { + } + + + public void visitFCONST( FCONST obj ) { + } + + + public void visitIUSHR( IUSHR obj ) { + } + + + public void visitBALOAD( BALOAD obj ) { + } + + + public void visitDUP2( DUP2 obj ) { + } + + + public void visitIF_ACMPEQ( IF_ACMPEQ obj ) { + } + + + public void visitIMPDEP1( IMPDEP1 obj ) { + } + + + public void visitMONITORENTER( MONITORENTER obj ) { + } + + + public void visitLSHL( LSHL obj ) { + } + + + public void visitDCMPG( DCMPG obj ) { + } + + + public void visitD2L( D2L obj ) { + } + + + public void visitIMPDEP2( IMPDEP2 obj ) { + } + + + public void visitL2D( L2D obj ) { + } + + + public void visitRET( RET obj ) { + } + + + public void visitIFGT( IFGT obj ) { + } + + + public void visitIXOR( IXOR obj ) { + } + + + public void visitINVOKEVIRTUAL( INVOKEVIRTUAL obj ) { + } + + + public void visitFASTORE( FASTORE obj ) { + } + + + public void visitIRETURN( IRETURN obj ) { + } + + + public void visitIF_ICMPNE( IF_ICMPNE obj ) { + } + + + public void visitFLOAD( FLOAD obj ) { + } + + + public void visitLDIV( LDIV obj ) { + } + + + public void visitPUTSTATIC( PUTSTATIC obj ) { + } + + + public void visitAALOAD( AALOAD obj ) { + } + + + public void visitD2I( D2I obj ) { + } + + + public void visitIF_ICMPEQ( IF_ICMPEQ obj ) { + } + + + public void visitAASTORE( AASTORE obj ) { + } + + + public void visitARETURN( ARETURN obj ) { + } + + + public void visitDUP2_X1( DUP2_X1 obj ) { + } + + + public void visitFNEG( FNEG obj ) { + } + + + public void visitGOTO_W( GOTO_W obj ) { + } + + + public void visitD2F( D2F obj ) { + } + + + public void visitGOTO( GOTO obj ) { + } + + + public void visitISUB( ISUB obj ) { + } + + + public void visitF2I( F2I obj ) { + } + + + public void visitDNEG( DNEG obj ) { + } + + + public void visitICONST( ICONST obj ) { + } + + + public void visitFDIV( FDIV obj ) { + } + + + public void visitI2B( I2B obj ) { + } + + + public void visitLNEG( LNEG obj ) { + } + + + public void visitLREM( LREM obj ) { + } + + + public void visitIMUL( IMUL obj ) { + } + + + public void visitIADD( IADD obj ) { + } + + + public void visitLSHR( LSHR obj ) { + } + + + public void visitLOOKUPSWITCH( LOOKUPSWITCH obj ) { + } + + + public void visitDUP_X1( DUP_X1 obj ) { + } + + + public void visitFCMPL( FCMPL obj ) { + } + + + public void visitI2C( I2C obj ) { + } + + + public void visitLMUL( LMUL obj ) { + } + + + public void visitLUSHR( LUSHR obj ) { + } + + + public void visitISHL( ISHL obj ) { + } + + + public void visitLALOAD( LALOAD obj ) { + } + + + public void visitASTORE( ASTORE obj ) { + } + + + public void visitANEWARRAY( ANEWARRAY obj ) { + } + + + public void visitFRETURN( FRETURN obj ) { + } + + + public void visitFADD( FADD obj ) { + } + + + public void visitBREAKPOINT( BREAKPOINT obj ) { + } +} diff --git a/src/org/apache/bcel/generic/ExceptionThrower.java b/src/org/apache/bcel/generic/ExceptionThrower.java new file mode 100644 index 0000000..570f47c --- /dev/null +++ b/src/org/apache/bcel/generic/ExceptionThrower.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denote an instruction that may throw a run-time or a linking + * exception (or both) during execution. This is not quite the truth + * as such; because all instructions may throw an + * java.lang.VirtualMachineError. These exceptions are omitted. + * + * The Lava Language Specification specifies exactly which + * RUN-TIME and which LINKING exceptions each + * instruction may throw which is reflected by the implementers. Due + * to the structure of the JVM specification, it may be possible that + * an Instruction implementing this interface returns a Class[] of + * size 0. + * + * Please note that we speak of an "exception" here when we mean any + * "Throwable" object; so this term is equally used for "Exception" + * and "Error" objects. + * + * @version $Id: ExceptionThrower.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public interface ExceptionThrower { + + public java.lang.Class[] getExceptions(); +} diff --git a/src/org/apache/bcel/generic/F2D.java b/src/org/apache/bcel/generic/F2D.java new file mode 100644 index 0000000..b3f9ac1 --- /dev/null +++ b/src/org/apache/bcel/generic/F2D.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * F2D - Convert float to double + *
      Stack: ..., value -> ..., result.word1, result.word2
      + * + * @version $Id: F2D.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class F2D extends ConversionInstruction { + + /** Convert float to double + */ + public F2D() { + super(org.apache.bcel.Constants.F2D); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitF2D(this); + } +} diff --git a/src/org/apache/bcel/generic/F2I.java b/src/org/apache/bcel/generic/F2I.java new file mode 100644 index 0000000..155d019 --- /dev/null +++ b/src/org/apache/bcel/generic/F2I.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * F2I - Convert float to int + *
      Stack: ..., value -> ..., result
      + * + * @version $Id: F2I.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class F2I extends ConversionInstruction { + + /** Convert float to int + */ + public F2I() { + super(org.apache.bcel.Constants.F2I); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitF2I(this); + } +} diff --git a/src/org/apache/bcel/generic/F2L.java b/src/org/apache/bcel/generic/F2L.java new file mode 100644 index 0000000..83ede65 --- /dev/null +++ b/src/org/apache/bcel/generic/F2L.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * F2L - Convert float to long + *
      Stack: ..., value -> ..., result.word1, result.word2
      + * + * @version $Id: F2L.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class F2L extends ConversionInstruction { + + /** Convert float to long + */ + public F2L() { + super(org.apache.bcel.Constants.F2L); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitF2L(this); + } +} diff --git a/src/org/apache/bcel/generic/FADD.java b/src/org/apache/bcel/generic/FADD.java new file mode 100644 index 0000000..88dcb1e --- /dev/null +++ b/src/org/apache/bcel/generic/FADD.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FADD - Add floats + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: FADD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FADD extends ArithmeticInstruction { + + /** Add floats + */ + public FADD() { + super(org.apache.bcel.Constants.FADD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitFADD(this); + } +} diff --git a/src/org/apache/bcel/generic/FALOAD.java b/src/org/apache/bcel/generic/FALOAD.java new file mode 100644 index 0000000..06fb7a3 --- /dev/null +++ b/src/org/apache/bcel/generic/FALOAD.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FALOAD - Load float from array + *
      Stack: ..., arrayref, index -> ..., value
      + * + * @version $Id: FALOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FALOAD extends ArrayInstruction implements StackProducer { + + /** Load float from array + */ + public FALOAD() { + super(org.apache.bcel.Constants.FALOAD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitFALOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/FASTORE.java b/src/org/apache/bcel/generic/FASTORE.java new file mode 100644 index 0000000..1545b49 --- /dev/null +++ b/src/org/apache/bcel/generic/FASTORE.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FASTORE - Store into float array + *
      Stack: ..., arrayref, index, value -> ...
      + * + * @version $Id: FASTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FASTORE extends ArrayInstruction implements StackConsumer { + + /** Store float into array + */ + public FASTORE() { + super(org.apache.bcel.Constants.FASTORE); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitFASTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/FCMPG.java b/src/org/apache/bcel/generic/FCMPG.java new file mode 100644 index 0000000..9ff626e --- /dev/null +++ b/src/org/apache/bcel/generic/FCMPG.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FCMPG - Compare floats: value1 > value2 + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: FCMPG.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FCMPG extends Instruction implements TypedInstruction, StackProducer, StackConsumer { + + public FCMPG() { + super(org.apache.bcel.Constants.FCMPG, (short) 1); + } + + + /** @return Type.FLOAT + */ + public Type getType( ConstantPoolGen cp ) { + return Type.FLOAT; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitFCMPG(this); + } +} diff --git a/src/org/apache/bcel/generic/FCMPL.java b/src/org/apache/bcel/generic/FCMPL.java new file mode 100644 index 0000000..7bc4bf2 --- /dev/null +++ b/src/org/apache/bcel/generic/FCMPL.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FCMPL - Compare floats: value1 < value2 + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: FCMPL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FCMPL extends Instruction implements TypedInstruction, StackProducer, StackConsumer { + + public FCMPL() { + super(org.apache.bcel.Constants.FCMPL, (short) 1); + } + + + /** @return Type.FLOAT + */ + public Type getType( ConstantPoolGen cp ) { + return Type.FLOAT; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitFCMPL(this); + } +} diff --git a/src/org/apache/bcel/generic/FCONST.java b/src/org/apache/bcel/generic/FCONST.java new file mode 100644 index 0000000..30bb0dc --- /dev/null +++ b/src/org/apache/bcel/generic/FCONST.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FCONST - Push 0.0, 1.0 or 2.0, other values cause an exception + * + *
      Stack: ... -> ..., 
      + * + * @version $Id: FCONST.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FCONST extends Instruction implements ConstantPushInstruction, TypedInstruction { + + private float value; + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + FCONST() { + } + + + public FCONST(float f) { + super(org.apache.bcel.Constants.FCONST_0, (short) 1); + if (f == 0.0) { + opcode = org.apache.bcel.Constants.FCONST_0; + } else if (f == 1.0) { + opcode = org.apache.bcel.Constants.FCONST_1; + } else if (f == 2.0) { + opcode = org.apache.bcel.Constants.FCONST_2; + } else { + throw new ClassGenException("FCONST can be used only for 0.0, 1.0 and 2.0: " + f); + } + value = f; + } + + + public Number getValue() { + return new Float(value); + } + + + /** @return Type.FLOAT + */ + public Type getType( ConstantPoolGen cp ) { + return Type.FLOAT; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitPushInstruction(this); + v.visitStackProducer(this); + v.visitTypedInstruction(this); + v.visitConstantPushInstruction(this); + v.visitFCONST(this); + } +} diff --git a/src/org/apache/bcel/generic/FDIV.java b/src/org/apache/bcel/generic/FDIV.java new file mode 100644 index 0000000..72a2019 --- /dev/null +++ b/src/org/apache/bcel/generic/FDIV.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FDIV - Divide floats + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: FDIV.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FDIV extends ArithmeticInstruction { + + /** Divide floats + */ + public FDIV() { + super(org.apache.bcel.Constants.FDIV); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitFDIV(this); + } +} diff --git a/src/org/apache/bcel/generic/FLOAD.java b/src/org/apache/bcel/generic/FLOAD.java new file mode 100644 index 0000000..beda2cb --- /dev/null +++ b/src/org/apache/bcel/generic/FLOAD.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FLOAD - Load float from local variable + *
      Stack ... -> ..., result
      + * + * @version $Id: FLOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FLOAD extends LoadInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + FLOAD() { + super(org.apache.bcel.Constants.FLOAD, org.apache.bcel.Constants.FLOAD_0); + } + + + /** Load float from local variable + * @param n index of local variable + */ + public FLOAD(int n) { + super(org.apache.bcel.Constants.FLOAD, org.apache.bcel.Constants.FLOAD_0, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + super.accept(v); + v.visitFLOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/FMUL.java b/src/org/apache/bcel/generic/FMUL.java new file mode 100644 index 0000000..2375ffe --- /dev/null +++ b/src/org/apache/bcel/generic/FMUL.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FMUL - Multiply floats + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: FMUL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FMUL extends ArithmeticInstruction { + + /** Multiply floats + */ + public FMUL() { + super(org.apache.bcel.Constants.FMUL); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitFMUL(this); + } +} diff --git a/src/org/apache/bcel/generic/FNEG.java b/src/org/apache/bcel/generic/FNEG.java new file mode 100644 index 0000000..a1c03ec --- /dev/null +++ b/src/org/apache/bcel/generic/FNEG.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FNEG - Negate float + *
      Stack: ..., value -> ..., result
      + * + * @version $Id: FNEG.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FNEG extends ArithmeticInstruction { + + public FNEG() { + super(org.apache.bcel.Constants.FNEG); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitFNEG(this); + } +} diff --git a/src/org/apache/bcel/generic/FREM.java b/src/org/apache/bcel/generic/FREM.java new file mode 100644 index 0000000..6227a63 --- /dev/null +++ b/src/org/apache/bcel/generic/FREM.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FREM - Remainder of floats + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: FREM.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FREM extends ArithmeticInstruction { + + /** Remainder of floats + */ + public FREM() { + super(org.apache.bcel.Constants.FREM); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitFREM(this); + } +} diff --git a/src/org/apache/bcel/generic/FRETURN.java b/src/org/apache/bcel/generic/FRETURN.java new file mode 100644 index 0000000..4676840 --- /dev/null +++ b/src/org/apache/bcel/generic/FRETURN.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FRETURN - Return float from method + *
      Stack: ..., value -> <empty>
      + * + * @version $Id: FRETURN.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FRETURN extends ReturnInstruction { + + /** Return float from method + */ + public FRETURN() { + super(org.apache.bcel.Constants.FRETURN); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitReturnInstruction(this); + v.visitFRETURN(this); + } +} diff --git a/src/org/apache/bcel/generic/FSTORE.java b/src/org/apache/bcel/generic/FSTORE.java new file mode 100644 index 0000000..ec4b950 --- /dev/null +++ b/src/org/apache/bcel/generic/FSTORE.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FSTORE - Store float into local variable + *
      Stack: ..., value -> ... 
      + * + * @version $Id: FSTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FSTORE extends StoreInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + FSTORE() { + super(org.apache.bcel.Constants.FSTORE, org.apache.bcel.Constants.FSTORE_0); + } + + + /** Store float into local variable + * @param n index of local variable + */ + public FSTORE(int n) { + super(org.apache.bcel.Constants.FSTORE, org.apache.bcel.Constants.FSTORE_0, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + super.accept(v); + v.visitFSTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/FSUB.java b/src/org/apache/bcel/generic/FSUB.java new file mode 100644 index 0000000..90a8dbb --- /dev/null +++ b/src/org/apache/bcel/generic/FSUB.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * FSUB - Substract floats + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: FSUB.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class FSUB extends ArithmeticInstruction { + + /** Substract floats + */ + public FSUB() { + super(org.apache.bcel.Constants.FSUB); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitFSUB(this); + } +} diff --git a/src/org/apache/bcel/generic/FieldGen.java b/src/org/apache/bcel/generic/FieldGen.java new file mode 100644 index 0000000..d9af25f --- /dev/null +++ b/src/org/apache/bcel/generic/FieldGen.java @@ -0,0 +1,357 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.Attribute; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.classfile.ConstantObject; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.ConstantValue; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.Utility; +import org.apache.bcel.util.BCELComparator; + +/** + * Template class for building up a field. The only extraordinary thing + * one can do is to add a constant value attribute to a field (which must of + * course be compatible with to the declared type). + * + * @version $Id: FieldGen.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Field + */ +public class FieldGen extends FieldGenOrMethodGen { + + private Object value = null; + private static BCELComparator _cmp = new BCELComparator() { + + public boolean equals( Object o1, Object o2 ) { + FieldGen THIS = (FieldGen) o1; + FieldGen THAT = (FieldGen) o2; + return THIS.getName().equals(THAT.getName()) + && THIS.getSignature().equals(THAT.getSignature()); + } + + + public int hashCode( Object o ) { + FieldGen THIS = (FieldGen) o; + return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + } + }; + + + /** + * Declare a field. If it is static (isStatic() == true) and has a + * basic type like int or String it may have an initial value + * associated with it as defined by setInitValue(). + * + * @param access_flags access qualifiers + * @param type field type + * @param name field name + * @param cp constant pool + */ + public FieldGen(int access_flags, Type type, String name, ConstantPoolGen cp) { + setAccessFlags(access_flags); + setType(type); + setName(name); + setConstantPool(cp); + } + + + /** + * Instantiate from existing field. + * + * @param field Field object + * @param cp constant pool (must contain the same entries as the field's constant pool) + */ + public FieldGen(Field field, ConstantPoolGen cp) { + this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp); + Attribute[] attrs = field.getAttributes(); + for (int i = 0; i < attrs.length; i++) { + if (attrs[i] instanceof ConstantValue) { + setValue(((ConstantValue) attrs[i]).getConstantValueIndex()); + } else { + addAttribute(attrs[i]); + } + } + } + + + private void setValue( int index ) { + ConstantPool cp = this.cp.getConstantPool(); + Constant c = cp.getConstant(index); + value = ((ConstantObject) c).getConstantValue(cp); + } + + + /** + * Set (optional) initial value of field, otherwise it will be set to null/0/false + * by the JVM automatically. + */ + public void setInitValue( String str ) { + checkType(new ObjectType("java.lang.String")); + if (str != null) { + value = str; + } + } + + + public void setInitValue( long l ) { + checkType(Type.LONG); + if (l != 0L) { + value = new Long(l); + } + } + + + public void setInitValue( int i ) { + checkType(Type.INT); + if (i != 0) { + value = new Integer(i); + } + } + + + public void setInitValue( short s ) { + checkType(Type.SHORT); + if (s != 0) { + value = new Integer(s); + } + } + + + public void setInitValue( char c ) { + checkType(Type.CHAR); + if (c != 0) { + value = new Integer(c); + } + } + + + public void setInitValue( byte b ) { + checkType(Type.BYTE); + if (b != 0) { + value = new Integer(b); + } + } + + + public void setInitValue( boolean b ) { + checkType(Type.BOOLEAN); + if (b) { + value = new Integer(1); + } + } + + + public void setInitValue( float f ) { + checkType(Type.FLOAT); + if (f != 0.0) { + value = new Float(f); + } + } + + + public void setInitValue( double d ) { + checkType(Type.DOUBLE); + if (d != 0.0) { + value = new Double(d); + } + } + + + /** Remove any initial value. + */ + public void cancelInitValue() { + value = null; + } + + + private void checkType( Type atype ) { + if (type == null) { + throw new ClassGenException("You haven't defined the type of the field yet"); + } + if (!isFinal()) { + throw new ClassGenException("Only final fields may have an initial value!"); + } + if (!type.equals(atype)) { + throw new ClassGenException("Types are not compatible: " + type + " vs. " + atype); + } + } + + + /** + * Get field object after having set up all necessary values. + */ + public Field getField() { + String signature = getSignature(); + int name_index = cp.addUtf8(name); + int signature_index = cp.addUtf8(signature); + if (value != null) { + checkType(type); + int index = addConstant(); + addAttribute(new ConstantValue(cp.addUtf8("ConstantValue"), 2, index, cp + .getConstantPool())); + } + return new Field(access_flags, name_index, signature_index, getAttributes(), cp + .getConstantPool()); + } + + + private int addConstant() { + switch (type.getType()) { + case Constants.T_INT: + case Constants.T_CHAR: + case Constants.T_BYTE: + case Constants.T_BOOLEAN: + case Constants.T_SHORT: + return cp.addInteger(((Integer) value).intValue()); + case Constants.T_FLOAT: + return cp.addFloat(((Float) value).floatValue()); + case Constants.T_DOUBLE: + return cp.addDouble(((Double) value).doubleValue()); + case Constants.T_LONG: + return cp.addLong(((Long) value).longValue()); + case Constants.T_REFERENCE: + return cp.addString(((String) value)); + default: + throw new RuntimeException("Oops: Unhandled : " + type.getType()); + } + } + + + public String getSignature() { + return type.getSignature(); + } + + private List observers; + + + /** Add observer for this object. + */ + public void addObserver( FieldObserver o ) { + if (observers == null) { + observers = new ArrayList(); + } + observers.add(o); + } + + + /** Remove observer for this object. + */ + public void removeObserver( FieldObserver o ) { + if (observers != null) { + observers.remove(o); + } + } + + + /** Call notify() method on all observers. This method is not called + * automatically whenever the state has changed, but has to be + * called by the user after he has finished editing the object. + */ + public void update() { + if (observers != null) { + for (Iterator e = observers.iterator(); e.hasNext();) { + ((FieldObserver) e.next()).notify(this); + } + } + } + + + public String getInitValue() { + if (value != null) { + return value.toString(); + } else { + return null; + } + } + + + /** + * Return string representation close to declaration format, + * `public static final short MAX = 100', e.g.. + * + * @return String representation of field + */ + public final String toString() { + String name, signature, access; // Short cuts to constant pool + access = Utility.accessToString(access_flags); + access = access.equals("") ? "" : (access + " "); + signature = type.toString(); + name = getName(); + StringBuffer buf = new StringBuffer(32); + buf.append(access).append(signature).append(" ").append(name); + String value = getInitValue(); + if (value != null) { + buf.append(" = ").append(value); + } + return buf.toString(); + } + + + /** @return deep copy of this field + */ + public FieldGen copy( ConstantPoolGen cp ) { + FieldGen fg = (FieldGen) clone(); + fg.setConstantPool(cp); + return fg; + } + + + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return _cmp; + } + + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator( BCELComparator comparator ) { + _cmp = comparator; + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default two FieldGen objects are said to be equal when + * their names and signatures are equal. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals( Object obj ) { + return _cmp.equals(this, obj); + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default return the hashcode of the field's name XOR signature. + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return _cmp.hashCode(this); + } +} diff --git a/src/org/apache/bcel/generic/FieldGenOrMethodGen.java b/src/org/apache/bcel/generic/FieldGenOrMethodGen.java new file mode 100644 index 0000000..c711cae --- /dev/null +++ b/src/org/apache/bcel/generic/FieldGenOrMethodGen.java @@ -0,0 +1,131 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.util.ArrayList; +import java.util.List; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.AccessFlags; +import org.apache.bcel.classfile.Attribute; + +/** + * Super class for FieldGen and MethodGen objects, since they have + * some methods in common! + * + * @version $Id: FieldGenOrMethodGen.java 410087 2006-05-29 12:12:19Z tcurdt $ + * @author M. Dahm + */ +public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAndTyped, Cloneable { + + protected String name; + protected Type type; + protected ConstantPoolGen cp; + private List attribute_vec = new ArrayList(); + + + protected FieldGenOrMethodGen() { + } + + + public void setType( Type type ) { + if (type.getType() == Constants.T_ADDRESS) { + throw new IllegalArgumentException("Type can not be " + type); + } + this.type = type; + } + + + public Type getType() { + return type; + } + + + /** @return name of method/field. + */ + public String getName() { + return name; + } + + + public void setName( String name ) { + this.name = name; + } + + + public ConstantPoolGen getConstantPool() { + return cp; + } + + + public void setConstantPool( ConstantPoolGen cp ) { + this.cp = cp; + } + + + /** + * Add an attribute to this method. Currently, the JVM knows about + * the `Code', `ConstantValue', `Synthetic' and `Exceptions' + * attributes. Other attributes will be ignored by the JVM but do no + * harm. + * + * @param a attribute to be added + */ + public void addAttribute( Attribute a ) { + attribute_vec.add(a); + } + + + /** + * Remove an attribute. + */ + public void removeAttribute( Attribute a ) { + attribute_vec.remove(a); + } + + + /** + * Remove all attributes. + */ + public void removeAttributes() { + attribute_vec.clear(); + } + + + /** + * @return all attributes of this method. + */ + public Attribute[] getAttributes() { + Attribute[] attributes = new Attribute[attribute_vec.size()]; + attribute_vec.toArray(attributes); + return attributes; + } + + + /** @return signature of method/field. + */ + public abstract String getSignature(); + + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + System.err.println(e); + return null; + } + } +} diff --git a/src/org/apache/bcel/generic/FieldInstruction.java b/src/org/apache/bcel/generic/FieldInstruction.java new file mode 100644 index 0000000..355b859 --- /dev/null +++ b/src/org/apache/bcel/generic/FieldInstruction.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.classfile.ConstantPool; + +/** + * Super class for the GET/PUTxxx family of instructions. + * + * @version $Id: FieldInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class FieldInstruction extends FieldOrMethod implements TypedInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + FieldInstruction() { + } + + + /** + * @param index to constant pool + */ + protected FieldInstruction(short opcode, int index) { + super(opcode, index); + } + + + /** + * @return mnemonic for instruction with symbolic references resolved + */ + public String toString( ConstantPool cp ) { + return org.apache.bcel.Constants.OPCODE_NAMES[opcode] + " " + + cp.constantToString(index, org.apache.bcel.Constants.CONSTANT_Fieldref); + } + + + /** @return size of field (1 or 2) + */ + protected int getFieldSize( ConstantPoolGen cpg ) { + return getType(cpg).getSize(); + } + + + /** @return return type of referenced field + */ + public Type getType( ConstantPoolGen cpg ) { + return getFieldType(cpg); + } + + + /** @return type of field + */ + public Type getFieldType( ConstantPoolGen cpg ) { + return Type.getType(getSignature(cpg)); + } + + + /** @return name of referenced field. + */ + public String getFieldName( ConstantPoolGen cpg ) { + return getName(cpg); + } +} diff --git a/src/org/apache/bcel/generic/FieldObserver.java b/src/org/apache/bcel/generic/FieldObserver.java new file mode 100644 index 0000000..1731abc --- /dev/null +++ b/src/org/apache/bcel/generic/FieldObserver.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Imnplement this interface if you're interested in changes to a FieldGen object + * and register yourself with addObserver(). + * + * @version $Id: FieldObserver.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface FieldObserver { + + public void notify( FieldGen field ); +} diff --git a/src/org/apache/bcel/generic/FieldOrMethod.java b/src/org/apache/bcel/generic/FieldOrMethod.java new file mode 100644 index 0000000..114f890 --- /dev/null +++ b/src/org/apache/bcel/generic/FieldOrMethod.java @@ -0,0 +1,128 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.classfile.ConstantCP; +import org.apache.bcel.classfile.ConstantNameAndType; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.ConstantUtf8; + +/** + * Super class for InvokeInstruction and FieldInstruction, since they have + * some methods in common! + * + * @version $Id: FieldOrMethod.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class FieldOrMethod extends CPInstruction implements LoadClass { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + FieldOrMethod() { + } + + + /** + * @param index to constant pool + */ + protected FieldOrMethod(short opcode, int index) { + super(opcode, index); + } + + + /** @return signature of referenced method/field. + */ + public String getSignature( ConstantPoolGen cpg ) { + ConstantPool cp = cpg.getConstantPool(); + ConstantCP cmr = (ConstantCP) cp.getConstant(index); + ConstantNameAndType cnat = (ConstantNameAndType) cp.getConstant(cmr.getNameAndTypeIndex()); + return ((ConstantUtf8) cp.getConstant(cnat.getSignatureIndex())).getBytes(); + } + + + /** @return name of referenced method/field. + */ + public String getName( ConstantPoolGen cpg ) { + ConstantPool cp = cpg.getConstantPool(); + ConstantCP cmr = (ConstantCP) cp.getConstant(index); + ConstantNameAndType cnat = (ConstantNameAndType) cp.getConstant(cmr.getNameAndTypeIndex()); + return ((ConstantUtf8) cp.getConstant(cnat.getNameIndex())).getBytes(); + } + + + /** @return name of the referenced class/interface + * @deprecated If the instruction references an array class, + * this method will return "java.lang.Object". + * For code generated by Java 1.5, this answer is + * sometimes wrong (e.g., if the "clone()" method is + * called on an array). A better idea is to use + * the getReferenceType() method, which correctly distinguishes + * between class types and array types. + */ + public String getClassName( ConstantPoolGen cpg ) { + ConstantPool cp = cpg.getConstantPool(); + ConstantCP cmr = (ConstantCP) cp.getConstant(index); + String className = cp.getConstantString(cmr.getClassIndex(), + org.apache.bcel.Constants.CONSTANT_Class); + if (className.startsWith("[")) { + // Turn array classes into java.lang.Object. + return "java.lang.Object"; + } + return className.replace('/', '.'); + } + + + /** @return type of the referenced class/interface + * @deprecated If the instruction references an array class, + * the ObjectType returned will be invalid. Use + * getReferenceType() instead. + */ + public ObjectType getClassType( ConstantPoolGen cpg ) { + return new ObjectType(getClassName(cpg)); + } + + + /** + * Return the reference type representing the class, interface, + * or array class referenced by the instruction. + * @param cpg the ConstantPoolGen used to create the instruction + * @return an ObjectType (if the referenced class type is a class + * or interface), or an ArrayType (if the referenced class + * type is an array class) + */ + public ReferenceType getReferenceType( ConstantPoolGen cpg ) { + ConstantPool cp = cpg.getConstantPool(); + ConstantCP cmr = (ConstantCP) cp.getConstant(index); + String className = cp.getConstantString(cmr.getClassIndex(), + org.apache.bcel.Constants.CONSTANT_Class); + if (className.startsWith("[")) { + return (ArrayType) Type.getType(className); + } else { + className = className.replace('/', '.'); + return new ObjectType(className); + } + } + + + /** @return type of the referenced class/interface + */ + public ObjectType getLoadClassType( ConstantPoolGen cpg ) { + return getClassType(cpg); + } +} diff --git a/src/org/apache/bcel/generic/GETFIELD.java b/src/org/apache/bcel/generic/GETFIELD.java new file mode 100644 index 0000000..1ca8708 --- /dev/null +++ b/src/org/apache/bcel/generic/GETFIELD.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.ExceptionConstants; + +/** + * GETFIELD - Fetch field from object + *
      Stack: ..., objectref -> ..., value
      + * OR + *
      Stack: ..., objectref -> ..., value.word1, value.word2
      + * + * @version $Id: GETFIELD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class GETFIELD extends FieldInstruction implements ExceptionThrower, StackConsumer, + StackProducer { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + GETFIELD() { + } + + + public GETFIELD(int index) { + super(Constants.GETFIELD, index); + } + + + public int produceStack( ConstantPoolGen cpg ) { + return getFieldSize(cpg); + } + + + public Class[] getExceptions() { + Class[] cs = new Class[2 + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length); + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length + 1] = ExceptionConstants.INCOMPATIBLE_CLASS_CHANGE_ERROR; + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length] = ExceptionConstants.NULL_POINTER_EXCEPTION; + return cs; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitStackConsumer(this); + v.visitStackProducer(this); + v.visitTypedInstruction(this); + v.visitLoadClass(this); + v.visitCPInstruction(this); + v.visitFieldOrMethod(this); + v.visitFieldInstruction(this); + v.visitGETFIELD(this); + } +} diff --git a/src/org/apache/bcel/generic/GETSTATIC.java b/src/org/apache/bcel/generic/GETSTATIC.java new file mode 100644 index 0000000..581bada --- /dev/null +++ b/src/org/apache/bcel/generic/GETSTATIC.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.ExceptionConstants; + +/** + * GETSTATIC - Fetch static field from class + *
      Stack: ..., -> ..., value
      + * OR + *
      Stack: ..., -> ..., value.word1, value.word2
      + * + * @version $Id: GETSTATIC.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class GETSTATIC extends FieldInstruction implements PushInstruction, ExceptionThrower { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + GETSTATIC() { + } + + + public GETSTATIC(int index) { + super(Constants.GETSTATIC, index); + } + + + public int produceStack( ConstantPoolGen cpg ) { + return getFieldSize(cpg); + } + + + public Class[] getExceptions() { + Class[] cs = new Class[1 + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length); + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length] = ExceptionConstants.INCOMPATIBLE_CLASS_CHANGE_ERROR; + return cs; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitPushInstruction(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitLoadClass(this); + v.visitCPInstruction(this); + v.visitFieldOrMethod(this); + v.visitFieldInstruction(this); + v.visitGETSTATIC(this); + } +} diff --git a/src/org/apache/bcel/generic/GOTO.java b/src/org/apache/bcel/generic/GOTO.java new file mode 100644 index 0000000..50777f6 --- /dev/null +++ b/src/org/apache/bcel/generic/GOTO.java @@ -0,0 +1,89 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * GOTO - Branch always (to relative offset, not absolute address) + * + * @version $Id: GOTO.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class GOTO extends GotoInstruction implements VariableLengthInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + GOTO() { + } + + + public GOTO(InstructionHandle target) { + super(org.apache.bcel.Constants.GOTO, target); + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + index = getTargetOffset(); + if (opcode == org.apache.bcel.Constants.GOTO) { + super.dump(out); + } else { // GOTO_W + index = getTargetOffset(); + out.writeByte(opcode); + out.writeInt(index); + } + } + + + /** Called in pass 2 of InstructionList.setPositions() in order to update + * the branch target, that may shift due to variable length instructions. + */ + protected int updatePosition( int offset, int max_offset ) { + int i = getTargetOffset(); // Depending on old position value + position += offset; // Position may be shifted by preceding expansions + if (Math.abs(i) >= (32767 - max_offset)) { // to large for short (estimate) + opcode = org.apache.bcel.Constants.GOTO_W; + length = 5; + return 2; // 5 - 3 + } + return 0; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitVariableLengthInstruction(this); + v.visitUnconditionalBranch(this); + v.visitBranchInstruction(this); + v.visitGotoInstruction(this); + v.visitGOTO(this); + } +} diff --git a/src/org/apache/bcel/generic/GOTO_W.java b/src/org/apache/bcel/generic/GOTO_W.java new file mode 100644 index 0000000..3909cb0 --- /dev/null +++ b/src/org/apache/bcel/generic/GOTO_W.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * GOTO_W - Branch always (to relative offset, not absolute address) + * + * @version $Id: GOTO_W.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class GOTO_W extends GotoInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + GOTO_W() { + } + + + public GOTO_W(InstructionHandle target) { + super(org.apache.bcel.Constants.GOTO_W, target); + length = 5; + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + index = getTargetOffset(); + out.writeByte(opcode); + out.writeInt(index); + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + index = bytes.readInt(); + length = 5; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitUnconditionalBranch(this); + v.visitBranchInstruction(this); + v.visitGotoInstruction(this); + v.visitGOTO_W(this); + } +} diff --git a/src/org/apache/bcel/generic/GotoInstruction.java b/src/org/apache/bcel/generic/GotoInstruction.java new file mode 100644 index 0000000..f263dad --- /dev/null +++ b/src/org/apache/bcel/generic/GotoInstruction.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Super class for GOTO + * + * @version $Id: GotoInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class GotoInstruction extends BranchInstruction implements UnconditionalBranch { + + GotoInstruction(short opcode, InstructionHandle target) { + super(opcode, target); + } + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + GotoInstruction() { + } +} diff --git a/src/org/apache/bcel/generic/I2B.java b/src/org/apache/bcel/generic/I2B.java new file mode 100644 index 0000000..b35057c --- /dev/null +++ b/src/org/apache/bcel/generic/I2B.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * I2B - Convert int to byte + *
      Stack: ..., value -> ..., result
      + * + * @version $Id: I2B.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class I2B extends ConversionInstruction { + + /** Convert int to byte + */ + public I2B() { + super(org.apache.bcel.Constants.I2B); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitI2B(this); + } +} diff --git a/src/org/apache/bcel/generic/I2C.java b/src/org/apache/bcel/generic/I2C.java new file mode 100644 index 0000000..b2a9849 --- /dev/null +++ b/src/org/apache/bcel/generic/I2C.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * I2C - Convert int to char + *
      Stack: ..., value -> ..., result
      + * + * @version $Id: I2C.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class I2C extends ConversionInstruction { + + /** Convert int to char + */ + public I2C() { + super(org.apache.bcel.Constants.I2C); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitI2C(this); + } +} diff --git a/src/org/apache/bcel/generic/I2D.java b/src/org/apache/bcel/generic/I2D.java new file mode 100644 index 0000000..cb002df --- /dev/null +++ b/src/org/apache/bcel/generic/I2D.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * I2D - Convert int to double + *
      Stack: ..., value -> ..., result.word1, result.word2
      + * + * @version $Id: I2D.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class I2D extends ConversionInstruction { + + /** Convert int to double + */ + public I2D() { + super(org.apache.bcel.Constants.I2D); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitI2D(this); + } +} diff --git a/src/org/apache/bcel/generic/I2F.java b/src/org/apache/bcel/generic/I2F.java new file mode 100644 index 0000000..235cab9 --- /dev/null +++ b/src/org/apache/bcel/generic/I2F.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * I2F - Convert int to float + *
      Stack: ..., value -> ..., result
      + * + * @version $Id: I2F.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class I2F extends ConversionInstruction { + + /** Convert int to float + */ + public I2F() { + super(org.apache.bcel.Constants.I2F); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitI2F(this); + } +} diff --git a/src/org/apache/bcel/generic/I2L.java b/src/org/apache/bcel/generic/I2L.java new file mode 100644 index 0000000..01bb564 --- /dev/null +++ b/src/org/apache/bcel/generic/I2L.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * I2L - Convert int to long + *
      Stack: ..., value -> ..., result.word1, result.word2
      + * + * @version $Id: I2L.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class I2L extends ConversionInstruction { + + /** Convert int to long + */ + public I2L() { + super(org.apache.bcel.Constants.I2L); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitI2L(this); + } +} diff --git a/src/org/apache/bcel/generic/I2S.java b/src/org/apache/bcel/generic/I2S.java new file mode 100644 index 0000000..3bbd2ae --- /dev/null +++ b/src/org/apache/bcel/generic/I2S.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * I2S - Convert int to short + *
      Stack: ..., value -> ..., result
      + * + * @version $Id: I2S.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class I2S extends ConversionInstruction { + + public I2S() { + super(org.apache.bcel.Constants.I2S); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitI2S(this); + } +} diff --git a/src/org/apache/bcel/generic/IADD.java b/src/org/apache/bcel/generic/IADD.java new file mode 100644 index 0000000..7fafc4f --- /dev/null +++ b/src/org/apache/bcel/generic/IADD.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IADD - Add ints + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: IADD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IADD extends ArithmeticInstruction { + + /** Add ints + */ + public IADD() { + super(org.apache.bcel.Constants.IADD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitIADD(this); + } +} diff --git a/src/org/apache/bcel/generic/IALOAD.java b/src/org/apache/bcel/generic/IALOAD.java new file mode 100644 index 0000000..b90d887 --- /dev/null +++ b/src/org/apache/bcel/generic/IALOAD.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IALOAD - Load int from array + *
      Stack: ..., arrayref, index -> ..., value
      + * + * @version $Id: IALOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IALOAD extends ArrayInstruction implements StackProducer { + + /** + * Load int from array + */ + public IALOAD() { + super(org.apache.bcel.Constants.IALOAD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitIALOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/IAND.java b/src/org/apache/bcel/generic/IAND.java new file mode 100644 index 0000000..fd6917e --- /dev/null +++ b/src/org/apache/bcel/generic/IAND.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IAND - Bitwise AND int + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: IAND.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IAND extends ArithmeticInstruction { + + public IAND() { + super(org.apache.bcel.Constants.IAND); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitIAND(this); + } +} diff --git a/src/org/apache/bcel/generic/IASTORE.java b/src/org/apache/bcel/generic/IASTORE.java new file mode 100644 index 0000000..0b87504 --- /dev/null +++ b/src/org/apache/bcel/generic/IASTORE.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IASTORE - Store into int array + *
      Stack: ..., arrayref, index, value -> ...
      + * + * @version $Id: IASTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IASTORE extends ArrayInstruction implements StackConsumer { + + /** + * Store into int array + */ + public IASTORE() { + super(org.apache.bcel.Constants.IASTORE); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitIASTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/ICONST.java b/src/org/apache/bcel/generic/ICONST.java new file mode 100644 index 0000000..98b9f00 --- /dev/null +++ b/src/org/apache/bcel/generic/ICONST.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ICONST - Push value between -1, ..., 5, other values cause an exception + * + *
      Stack: ... -> ..., 
      + * + * @version $Id: ICONST.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ICONST extends Instruction implements ConstantPushInstruction, TypedInstruction { + + private int value; + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + ICONST() { + } + + + public ICONST(int i) { + super(org.apache.bcel.Constants.ICONST_0, (short) 1); + if ((i >= -1) && (i <= 5)) { + opcode = (short) (org.apache.bcel.Constants.ICONST_0 + i); // Even works for i == -1 + } else { + throw new ClassGenException("ICONST can be used only for value between -1 and 5: " + i); + } + value = i; + } + + + public Number getValue() { + return new Integer(value); + } + + + /** @return Type.INT + */ + public Type getType( ConstantPoolGen cp ) { + return Type.INT; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitPushInstruction(this); + v.visitStackProducer(this); + v.visitTypedInstruction(this); + v.visitConstantPushInstruction(this); + v.visitICONST(this); + } +} diff --git a/src/org/apache/bcel/generic/IDIV.java b/src/org/apache/bcel/generic/IDIV.java new file mode 100644 index 0000000..eb4d404 --- /dev/null +++ b/src/org/apache/bcel/generic/IDIV.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IDIV - Divide ints + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: IDIV.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IDIV extends ArithmeticInstruction implements ExceptionThrower { + + /** Divide ints + */ + public IDIV() { + super(org.apache.bcel.Constants.IDIV); + } + + + /** @return exceptions this instruction may cause + */ + public Class[] getExceptions() { + return new Class[] { + org.apache.bcel.ExceptionConstants.ARITHMETIC_EXCEPTION + }; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitIDIV(this); + } +} diff --git a/src/org/apache/bcel/generic/IFEQ.java b/src/org/apache/bcel/generic/IFEQ.java new file mode 100644 index 0000000..9747dcc --- /dev/null +++ b/src/org/apache/bcel/generic/IFEQ.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IFEQ - Branch if int comparison with zero succeeds + * + *
      Stack: ..., value -> ...
      + * + * @version $Id: IFEQ.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IFEQ extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IFEQ() { + } + + + public IFEQ(InstructionHandle target) { + super(org.apache.bcel.Constants.IFEQ, target); + } + + + /** + * @return negation of instruction, e.g. IFEQ.negate() == IFNE + */ + public IfInstruction negate() { + return new IFNE(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIFEQ(this); + } +} diff --git a/src/org/apache/bcel/generic/IFGE.java b/src/org/apache/bcel/generic/IFGE.java new file mode 100644 index 0000000..f4478ad --- /dev/null +++ b/src/org/apache/bcel/generic/IFGE.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IFGE - Branch if int comparison with zero succeeds + * + *
      Stack: ..., value -> ...
      + * + * @version $Id: IFGE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IFGE extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IFGE() { + } + + + public IFGE(InstructionHandle target) { + super(org.apache.bcel.Constants.IFGE, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IFLT(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIFGE(this); + } +} diff --git a/src/org/apache/bcel/generic/IFGT.java b/src/org/apache/bcel/generic/IFGT.java new file mode 100644 index 0000000..990c163 --- /dev/null +++ b/src/org/apache/bcel/generic/IFGT.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IFGT - Branch if int comparison with zero succeeds + * + *
      Stack: ..., value -> ...
      + * + * @version $Id: IFGT.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IFGT extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IFGT() { + } + + + public IFGT(InstructionHandle target) { + super(org.apache.bcel.Constants.IFGT, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IFLE(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIFGT(this); + } +} diff --git a/src/org/apache/bcel/generic/IFLE.java b/src/org/apache/bcel/generic/IFLE.java new file mode 100644 index 0000000..d8f5f37 --- /dev/null +++ b/src/org/apache/bcel/generic/IFLE.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IFLE - Branch if int comparison with zero succeeds + * + *
      Stack: ..., value -> ...
      + * + * @version $Id: IFLE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IFLE extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IFLE() { + } + + + public IFLE(InstructionHandle target) { + super(org.apache.bcel.Constants.IFLE, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IFGT(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIFLE(this); + } +} diff --git a/src/org/apache/bcel/generic/IFLT.java b/src/org/apache/bcel/generic/IFLT.java new file mode 100644 index 0000000..5a048a6 --- /dev/null +++ b/src/org/apache/bcel/generic/IFLT.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IFLT - Branch if int comparison with zero succeeds + * + *
      Stack: ..., value -> ...
      + * + * @version $Id: IFLT.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IFLT extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IFLT() { + } + + + public IFLT(InstructionHandle target) { + super(org.apache.bcel.Constants.IFLT, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IFGE(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIFLT(this); + } +} diff --git a/src/org/apache/bcel/generic/IFNE.java b/src/org/apache/bcel/generic/IFNE.java new file mode 100644 index 0000000..2658aa1 --- /dev/null +++ b/src/org/apache/bcel/generic/IFNE.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IFNE - Branch if int comparison with zero succeeds + * + *
      Stack: ..., value -> ...
      + * + * @version $Id: IFNE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IFNE extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IFNE() { + } + + + public IFNE(InstructionHandle target) { + super(org.apache.bcel.Constants.IFNE, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IFEQ(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIFNE(this); + } +} diff --git a/src/org/apache/bcel/generic/IFNONNULL.java b/src/org/apache/bcel/generic/IFNONNULL.java new file mode 100644 index 0000000..e986bdc --- /dev/null +++ b/src/org/apache/bcel/generic/IFNONNULL.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IFNONNULL - Branch if reference is not null + * + *
      Stack: ..., reference -> ...
      + * + * @version $Id: IFNONNULL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IFNONNULL extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IFNONNULL() { + } + + + public IFNONNULL(InstructionHandle target) { + super(org.apache.bcel.Constants.IFNONNULL, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IFNULL(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIFNONNULL(this); + } +} diff --git a/src/org/apache/bcel/generic/IFNULL.java b/src/org/apache/bcel/generic/IFNULL.java new file mode 100644 index 0000000..0e91ca1 --- /dev/null +++ b/src/org/apache/bcel/generic/IFNULL.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IFNULL - Branch if reference is not null + * + *
      Stack: ..., reference -> ...
      + * + * @version $Id: IFNULL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IFNULL extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IFNULL() { + } + + + public IFNULL(InstructionHandle target) { + super(org.apache.bcel.Constants.IFNULL, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IFNONNULL(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIFNULL(this); + } +} diff --git a/src/org/apache/bcel/generic/IF_ACMPEQ.java b/src/org/apache/bcel/generic/IF_ACMPEQ.java new file mode 100644 index 0000000..42eed3b --- /dev/null +++ b/src/org/apache/bcel/generic/IF_ACMPEQ.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IF_ACMPEQ - Branch if reference comparison succeeds + * + *
      Stack: ..., value1, value2 -> ...
      + * + * @version $Id: IF_ACMPEQ.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IF_ACMPEQ extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IF_ACMPEQ() { + } + + + public IF_ACMPEQ(InstructionHandle target) { + super(org.apache.bcel.Constants.IF_ACMPEQ, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IF_ACMPNE(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIF_ACMPEQ(this); + } +} diff --git a/src/org/apache/bcel/generic/IF_ACMPNE.java b/src/org/apache/bcel/generic/IF_ACMPNE.java new file mode 100644 index 0000000..14fc230 --- /dev/null +++ b/src/org/apache/bcel/generic/IF_ACMPNE.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IF_ACMPNE - Branch if reference comparison doesn't succeed + * + *
      Stack: ..., value1, value2 -> ...
      + * + * @version $Id: IF_ACMPNE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IF_ACMPNE extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IF_ACMPNE() { + } + + + public IF_ACMPNE(InstructionHandle target) { + super(org.apache.bcel.Constants.IF_ACMPNE, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IF_ACMPEQ(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIF_ACMPNE(this); + } +} diff --git a/src/org/apache/bcel/generic/IF_ICMPEQ.java b/src/org/apache/bcel/generic/IF_ICMPEQ.java new file mode 100644 index 0000000..5308842 --- /dev/null +++ b/src/org/apache/bcel/generic/IF_ICMPEQ.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IF_ICMPEQ - Branch if int comparison succeeds + * + *
      Stack: ..., value1, value2 -> ...
      + * + * @version $Id: IF_ICMPEQ.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IF_ICMPEQ extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IF_ICMPEQ() { + } + + + public IF_ICMPEQ(InstructionHandle target) { + super(org.apache.bcel.Constants.IF_ICMPEQ, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IF_ICMPNE(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIF_ICMPEQ(this); + } +} diff --git a/src/org/apache/bcel/generic/IF_ICMPGE.java b/src/org/apache/bcel/generic/IF_ICMPGE.java new file mode 100644 index 0000000..9e23be2 --- /dev/null +++ b/src/org/apache/bcel/generic/IF_ICMPGE.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IF_ICMPGE - Branch if int comparison succeeds + * + *
      Stack: ..., value1, value2 -> ...
      + * + * @version $Id: IF_ICMPGE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IF_ICMPGE extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IF_ICMPGE() { + } + + + public IF_ICMPGE(InstructionHandle target) { + super(org.apache.bcel.Constants.IF_ICMPGE, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IF_ICMPLT(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIF_ICMPGE(this); + } +} diff --git a/src/org/apache/bcel/generic/IF_ICMPGT.java b/src/org/apache/bcel/generic/IF_ICMPGT.java new file mode 100644 index 0000000..32f1ece --- /dev/null +++ b/src/org/apache/bcel/generic/IF_ICMPGT.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IF_ICMPGT - Branch if int comparison succeeds + * + *
      Stack: ..., value1, value2 -> ...
      + * + * @version $Id: IF_ICMPGT.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IF_ICMPGT extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IF_ICMPGT() { + } + + + public IF_ICMPGT(InstructionHandle target) { + super(org.apache.bcel.Constants.IF_ICMPGT, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IF_ICMPLE(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIF_ICMPGT(this); + } +} diff --git a/src/org/apache/bcel/generic/IF_ICMPLE.java b/src/org/apache/bcel/generic/IF_ICMPLE.java new file mode 100644 index 0000000..381a78b --- /dev/null +++ b/src/org/apache/bcel/generic/IF_ICMPLE.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IF_ICMPLE - Branch if int comparison succeeds + * + *
      Stack: ..., value1, value2 -> ...
      + * + * @version $Id: IF_ICMPLE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IF_ICMPLE extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IF_ICMPLE() { + } + + + public IF_ICMPLE(InstructionHandle target) { + super(org.apache.bcel.Constants.IF_ICMPLE, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IF_ICMPGT(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIF_ICMPLE(this); + } +} diff --git a/src/org/apache/bcel/generic/IF_ICMPLT.java b/src/org/apache/bcel/generic/IF_ICMPLT.java new file mode 100644 index 0000000..c9e269e --- /dev/null +++ b/src/org/apache/bcel/generic/IF_ICMPLT.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IF_ICMPLT - Branch if int comparison succeeds + * + *
      Stack: ..., value1, value2 -> ...
      + * + * @version $Id: IF_ICMPLT.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IF_ICMPLT extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IF_ICMPLT() { + } + + + public IF_ICMPLT(InstructionHandle target) { + super(org.apache.bcel.Constants.IF_ICMPLT, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IF_ICMPGE(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIF_ICMPLT(this); + } +} diff --git a/src/org/apache/bcel/generic/IF_ICMPNE.java b/src/org/apache/bcel/generic/IF_ICMPNE.java new file mode 100644 index 0000000..537b416 --- /dev/null +++ b/src/org/apache/bcel/generic/IF_ICMPNE.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IF_ICMPNE - Branch if int comparison doesn't succeed + * + *
      Stack: ..., value1, value2 -> ...
      + * + * @version $Id: IF_ICMPNE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IF_ICMPNE extends IfInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IF_ICMPNE() { + } + + + public IF_ICMPNE(InstructionHandle target) { + super(org.apache.bcel.Constants.IF_ICMPNE, target); + } + + + /** + * @return negation of instruction + */ + public IfInstruction negate() { + return new IF_ICMPEQ(target); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitBranchInstruction(this); + v.visitIfInstruction(this); + v.visitIF_ICMPNE(this); + } +} diff --git a/src/org/apache/bcel/generic/IINC.java b/src/org/apache/bcel/generic/IINC.java new file mode 100644 index 0000000..72af3ab --- /dev/null +++ b/src/org/apache/bcel/generic/IINC.java @@ -0,0 +1,158 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * IINC - Increment local variable by constant + * + * @version $Id: IINC.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IINC extends LocalVariableInstruction { + + private boolean wide; + private int c; + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IINC() { + } + + + /** + * @param n index of local variable + * @param c increment factor + */ + public IINC(int n, int c) { + super(); // Default behaviour of LocalVariableInstruction causes error + this.opcode = org.apache.bcel.Constants.IINC; + this.length = (short) 3; + setIndex(n); // May set wide as side effect + setIncrement(c); + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + if (wide) { + out.writeByte(org.apache.bcel.Constants.WIDE); + } + out.writeByte(opcode); + if (wide) { + out.writeShort(n); + out.writeShort(c); + } else { + out.writeByte(n); + out.writeByte(c); + } + } + + + private final void setWide() { + wide = (n > org.apache.bcel.Constants.MAX_BYTE) || (Math.abs(c) > Byte.MAX_VALUE); + if (wide) { + length = 6; // wide byte included + } else { + length = 3; + } + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + this.wide = wide; + if (wide) { + length = 6; + n = bytes.readUnsignedShort(); + c = bytes.readShort(); + } else { + length = 3; + n = bytes.readUnsignedByte(); + c = bytes.readByte(); + } + } + + + /** + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + return super.toString(verbose) + " " + c; + } + + + /** + * Set index of local variable. + */ + public final void setIndex( int n ) { + if (n < 0) { + throw new ClassGenException("Negative index value: " + n); + } + this.n = n; + setWide(); + } + + + /** + * @return increment factor + */ + public final int getIncrement() { + return c; + } + + + /** + * Set increment factor. + */ + public final void setIncrement( int c ) { + this.c = c; + setWide(); + } + + + /** @return int type + */ + public Type getType( ConstantPoolGen cp ) { + return Type.INT; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitLocalVariableInstruction(this); + v.visitIINC(this); + } +} diff --git a/src/org/apache/bcel/generic/ILOAD.java b/src/org/apache/bcel/generic/ILOAD.java new file mode 100644 index 0000000..64368d3 --- /dev/null +++ b/src/org/apache/bcel/generic/ILOAD.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ILOAD - Load int from local variable onto stack + *
      Stack: ... -> ..., result
      + * + * @version $Id: ILOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ILOAD extends LoadInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + ILOAD() { + super(org.apache.bcel.Constants.ILOAD, org.apache.bcel.Constants.ILOAD_0); + } + + + /** Load int from local variable + * @param n index of local variable + */ + public ILOAD(int n) { + super(org.apache.bcel.Constants.ILOAD, org.apache.bcel.Constants.ILOAD_0, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + super.accept(v); + v.visitILOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/IMPDEP1.java b/src/org/apache/bcel/generic/IMPDEP1.java new file mode 100644 index 0000000..2d16659 --- /dev/null +++ b/src/org/apache/bcel/generic/IMPDEP1.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IMPDEP1 - Implementation dependent + * + * @version $Id: IMPDEP1.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IMPDEP1 extends Instruction { + + public IMPDEP1() { + super(org.apache.bcel.Constants.IMPDEP1, (short) 1); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitIMPDEP1(this); + } +} diff --git a/src/org/apache/bcel/generic/IMPDEP2.java b/src/org/apache/bcel/generic/IMPDEP2.java new file mode 100644 index 0000000..4efdb87 --- /dev/null +++ b/src/org/apache/bcel/generic/IMPDEP2.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IMPDEP2 - Implementation dependent + * + * @version $Id: IMPDEP2.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IMPDEP2 extends Instruction { + + public IMPDEP2() { + super(org.apache.bcel.Constants.IMPDEP2, (short) 1); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitIMPDEP2(this); + } +} diff --git a/src/org/apache/bcel/generic/IMUL.java b/src/org/apache/bcel/generic/IMUL.java new file mode 100644 index 0000000..bb212c2 --- /dev/null +++ b/src/org/apache/bcel/generic/IMUL.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IMUL - Multiply ints + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: IMUL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IMUL extends ArithmeticInstruction { + + /** Multiply ints + */ + public IMUL() { + super(org.apache.bcel.Constants.IMUL); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitIMUL(this); + } +} diff --git a/src/org/apache/bcel/generic/INEG.java b/src/org/apache/bcel/generic/INEG.java new file mode 100644 index 0000000..c7ef3c8 --- /dev/null +++ b/src/org/apache/bcel/generic/INEG.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * INEG - Negate int + *
      Stack: ..., value -> ..., result
      + * + * @version $Id: INEG.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class INEG extends ArithmeticInstruction { + + public INEG() { + super(org.apache.bcel.Constants.INEG); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitINEG(this); + } +} diff --git a/src/org/apache/bcel/generic/INSTANCEOF.java b/src/org/apache/bcel/generic/INSTANCEOF.java new file mode 100644 index 0000000..139f708 --- /dev/null +++ b/src/org/apache/bcel/generic/INSTANCEOF.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * INSTANCEOF - Determine if object is of given type + *
      Stack: ..., objectref -> ..., result
      + * + * @version $Id: INSTANCEOF.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class INSTANCEOF extends CPInstruction implements LoadClass, ExceptionThrower, + StackProducer, StackConsumer { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + INSTANCEOF() { + } + + + public INSTANCEOF(int index) { + super(org.apache.bcel.Constants.INSTANCEOF, index); + } + + + public Class[] getExceptions() { + return org.apache.bcel.ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION; + } + + + public ObjectType getLoadClassType( ConstantPoolGen cpg ) { + Type t = getType(cpg); + if (t instanceof ArrayType) { + t = ((ArrayType) t).getBasicType(); + } + return (t instanceof ObjectType) ? (ObjectType) t : null; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitLoadClass(this); + v.visitExceptionThrower(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitTypedInstruction(this); + v.visitCPInstruction(this); + v.visitINSTANCEOF(this); + } +} diff --git a/src/org/apache/bcel/generic/INVOKEINTERFACE.java b/src/org/apache/bcel/generic/INVOKEINTERFACE.java new file mode 100644 index 0000000..99da626 --- /dev/null +++ b/src/org/apache/bcel/generic/INVOKEINTERFACE.java @@ -0,0 +1,132 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; +import org.apache.bcel.ExceptionConstants; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.util.ByteSequence; + +/** + * INVOKEINTERFACE - Invoke interface method + *
      Stack: ..., objectref, [arg1, [arg2 ...]] -> ...
      + * + * @version $Id: INVOKEINTERFACE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class INVOKEINTERFACE extends InvokeInstruction { + + private int nargs; // Number of arguments on stack (number of stack slots), called "count" in vmspec2 + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + INVOKEINTERFACE() { + } + + + public INVOKEINTERFACE(int index, int nargs) { + super(Constants.INVOKEINTERFACE, index); + length = 5; + if (nargs < 1) { + throw new ClassGenException("Number of arguments must be > 0 " + nargs); + } + this.nargs = nargs; + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + out.writeByte(opcode); + out.writeShort(index); + out.writeByte(nargs); + out.writeByte(0); + } + + + /** + * The count argument according to the Java Language Specification, + * Second Edition. + */ + public int getCount() { + return nargs; + } + + + /** + * Read needed data (i.e., index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + super.initFromFile(bytes, wide); + length = 5; + nargs = bytes.readUnsignedByte(); + bytes.readByte(); // Skip 0 byte + } + + + /** + * @return mnemonic for instruction with symbolic references resolved + */ + public String toString( ConstantPool cp ) { + return super.toString(cp) + " " + nargs; + } + + + public int consumeStack( ConstantPoolGen cpg ) { // nargs is given in byte-code + return nargs; // nargs includes this reference + } + + + public Class[] getExceptions() { + Class[] cs = new Class[4 + ExceptionConstants.EXCS_INTERFACE_METHOD_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_INTERFACE_METHOD_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_INTERFACE_METHOD_RESOLUTION.length); + cs[ExceptionConstants.EXCS_INTERFACE_METHOD_RESOLUTION.length + 3] = ExceptionConstants.INCOMPATIBLE_CLASS_CHANGE_ERROR; + cs[ExceptionConstants.EXCS_INTERFACE_METHOD_RESOLUTION.length + 2] = ExceptionConstants.ILLEGAL_ACCESS_ERROR; + cs[ExceptionConstants.EXCS_INTERFACE_METHOD_RESOLUTION.length + 1] = ExceptionConstants.ABSTRACT_METHOD_ERROR; + cs[ExceptionConstants.EXCS_INTERFACE_METHOD_RESOLUTION.length] = ExceptionConstants.UNSATISFIED_LINK_ERROR; + return cs; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitStackProducer(this); + v.visitLoadClass(this); + v.visitCPInstruction(this); + v.visitFieldOrMethod(this); + v.visitInvokeInstruction(this); + v.visitINVOKEINTERFACE(this); + } +} diff --git a/src/org/apache/bcel/generic/INVOKESPECIAL.java b/src/org/apache/bcel/generic/INVOKESPECIAL.java new file mode 100644 index 0000000..d960c49 --- /dev/null +++ b/src/org/apache/bcel/generic/INVOKESPECIAL.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.ExceptionConstants; + +/** + * INVOKESPECIAL - Invoke instance method; special handling for superclass, private + * and instance initialization method invocations + * + *
      Stack: ..., objectref, [arg1, [arg2 ...]] -> ...
      + * + * @version $Id: INVOKESPECIAL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class INVOKESPECIAL extends InvokeInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + INVOKESPECIAL() { + } + + + public INVOKESPECIAL(int index) { + super(Constants.INVOKESPECIAL, index); + } + + + public Class[] getExceptions() { + Class[] cs = new Class[4 + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length); + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length + 3] = ExceptionConstants.UNSATISFIED_LINK_ERROR; + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length + 2] = ExceptionConstants.ABSTRACT_METHOD_ERROR; + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length + 1] = ExceptionConstants.INCOMPATIBLE_CLASS_CHANGE_ERROR; + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length] = ExceptionConstants.NULL_POINTER_EXCEPTION; + return cs; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitStackProducer(this); + v.visitLoadClass(this); + v.visitCPInstruction(this); + v.visitFieldOrMethod(this); + v.visitInvokeInstruction(this); + v.visitINVOKESPECIAL(this); + } +} diff --git a/src/org/apache/bcel/generic/INVOKESTATIC.java b/src/org/apache/bcel/generic/INVOKESTATIC.java new file mode 100644 index 0000000..6300182 --- /dev/null +++ b/src/org/apache/bcel/generic/INVOKESTATIC.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.ExceptionConstants; + +/** + * INVOKESTATIC - Invoke a class (static) method + * + *
      Stack: ..., [arg1, [arg2 ...]] -> ...
      + * + * @version $Id: INVOKESTATIC.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class INVOKESTATIC extends InvokeInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + INVOKESTATIC() { + } + + + public INVOKESTATIC(int index) { + super(Constants.INVOKESTATIC, index); + } + + + public Class[] getExceptions() { + Class[] cs = new Class[2 + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length); + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length] = ExceptionConstants.UNSATISFIED_LINK_ERROR; + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length + 1] = ExceptionConstants.INCOMPATIBLE_CLASS_CHANGE_ERROR; + return cs; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitStackProducer(this); + v.visitLoadClass(this); + v.visitCPInstruction(this); + v.visitFieldOrMethod(this); + v.visitInvokeInstruction(this); + v.visitINVOKESTATIC(this); + } +} diff --git a/src/org/apache/bcel/generic/INVOKEVIRTUAL.java b/src/org/apache/bcel/generic/INVOKEVIRTUAL.java new file mode 100644 index 0000000..d4faaac --- /dev/null +++ b/src/org/apache/bcel/generic/INVOKEVIRTUAL.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.ExceptionConstants; + +/** + * INVOKEVIRTUAL - Invoke instance method; dispatch based on class + * + *
      Stack: ..., objectref, [arg1, [arg2 ...]] -> ...
      + * + * @version $Id: INVOKEVIRTUAL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class INVOKEVIRTUAL extends InvokeInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + INVOKEVIRTUAL() { + } + + + public INVOKEVIRTUAL(int index) { + super(Constants.INVOKEVIRTUAL, index); + } + + + public Class[] getExceptions() { + Class[] cs = new Class[4 + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length); + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length + 3] = ExceptionConstants.UNSATISFIED_LINK_ERROR; + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length + 2] = ExceptionConstants.ABSTRACT_METHOD_ERROR; + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length + 1] = ExceptionConstants.INCOMPATIBLE_CLASS_CHANGE_ERROR; + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length] = ExceptionConstants.NULL_POINTER_EXCEPTION; + return cs; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitStackProducer(this); + v.visitLoadClass(this); + v.visitCPInstruction(this); + v.visitFieldOrMethod(this); + v.visitInvokeInstruction(this); + v.visitINVOKEVIRTUAL(this); + } +} diff --git a/src/org/apache/bcel/generic/IOR.java b/src/org/apache/bcel/generic/IOR.java new file mode 100644 index 0000000..c1c6598 --- /dev/null +++ b/src/org/apache/bcel/generic/IOR.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IOR - Bitwise OR int + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: IOR.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IOR extends ArithmeticInstruction { + + public IOR() { + super(org.apache.bcel.Constants.IOR); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitIOR(this); + } +} diff --git a/src/org/apache/bcel/generic/IREM.java b/src/org/apache/bcel/generic/IREM.java new file mode 100644 index 0000000..9504b9d --- /dev/null +++ b/src/org/apache/bcel/generic/IREM.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IREM - Remainder of int + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: IREM.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IREM extends ArithmeticInstruction implements ExceptionThrower { + + /** Remainder of ints + */ + public IREM() { + super(org.apache.bcel.Constants.IREM); + } + + + /** @return exceptions this instruction may cause + */ + public Class[] getExceptions() { + return new Class[] { + org.apache.bcel.ExceptionConstants.ARITHMETIC_EXCEPTION + }; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitIREM(this); + } +} diff --git a/src/org/apache/bcel/generic/IRETURN.java b/src/org/apache/bcel/generic/IRETURN.java new file mode 100644 index 0000000..61d45bd --- /dev/null +++ b/src/org/apache/bcel/generic/IRETURN.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IRETURN - Return int from method + *
      Stack: ..., value -> <empty>
      + * + * @version $Id: IRETURN.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IRETURN extends ReturnInstruction { + + /** Return int from method + */ + public IRETURN() { + super(org.apache.bcel.Constants.IRETURN); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitReturnInstruction(this); + v.visitIRETURN(this); + } +} diff --git a/src/org/apache/bcel/generic/ISHL.java b/src/org/apache/bcel/generic/ISHL.java new file mode 100644 index 0000000..510773c --- /dev/null +++ b/src/org/apache/bcel/generic/ISHL.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ISHL - Arithmetic shift left int + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: ISHL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ISHL extends ArithmeticInstruction { + + public ISHL() { + super(org.apache.bcel.Constants.ISHL); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitISHL(this); + } +} diff --git a/src/org/apache/bcel/generic/ISHR.java b/src/org/apache/bcel/generic/ISHR.java new file mode 100644 index 0000000..2bc71a3 --- /dev/null +++ b/src/org/apache/bcel/generic/ISHR.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ISHR - Arithmetic shift right int + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: ISHR.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ISHR extends ArithmeticInstruction { + + public ISHR() { + super(org.apache.bcel.Constants.ISHR); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitISHR(this); + } +} diff --git a/src/org/apache/bcel/generic/ISTORE.java b/src/org/apache/bcel/generic/ISTORE.java new file mode 100644 index 0000000..bca07c1 --- /dev/null +++ b/src/org/apache/bcel/generic/ISTORE.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ISTORE - Store int from stack into local variable + *
      Stack: ..., value -> ... 
      + * + * @version $Id: ISTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ISTORE extends StoreInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + ISTORE() { + super(org.apache.bcel.Constants.ISTORE, org.apache.bcel.Constants.ISTORE_0); + } + + + /** Store int into local variable + * @param n index of local variable + */ + public ISTORE(int n) { + super(org.apache.bcel.Constants.ISTORE, org.apache.bcel.Constants.ISTORE_0, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + super.accept(v); + v.visitISTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/ISUB.java b/src/org/apache/bcel/generic/ISUB.java new file mode 100644 index 0000000..9885687 --- /dev/null +++ b/src/org/apache/bcel/generic/ISUB.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * ISUB - Substract ints + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: ISUB.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ISUB extends ArithmeticInstruction { + + /** Substract ints + */ + public ISUB() { + super(org.apache.bcel.Constants.ISUB); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitISUB(this); + } +} diff --git a/src/org/apache/bcel/generic/IUSHR.java b/src/org/apache/bcel/generic/IUSHR.java new file mode 100644 index 0000000..6e5cc1c --- /dev/null +++ b/src/org/apache/bcel/generic/IUSHR.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IUSHR - Logical shift right int + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: IUSHR.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IUSHR extends ArithmeticInstruction { + + public IUSHR() { + super(org.apache.bcel.Constants.IUSHR); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitIUSHR(this); + } +} diff --git a/src/org/apache/bcel/generic/IXOR.java b/src/org/apache/bcel/generic/IXOR.java new file mode 100644 index 0000000..0e3472f --- /dev/null +++ b/src/org/apache/bcel/generic/IXOR.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * IXOR - Bitwise XOR int + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: IXOR.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class IXOR extends ArithmeticInstruction { + + public IXOR() { + super(org.apache.bcel.Constants.IXOR); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitIXOR(this); + } +} diff --git a/src/org/apache/bcel/generic/IfInstruction.java b/src/org/apache/bcel/generic/IfInstruction.java new file mode 100644 index 0000000..33af0c0 --- /dev/null +++ b/src/org/apache/bcel/generic/IfInstruction.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Super class for the IFxxx family of instructions. + * + * @version $Id: IfInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class IfInstruction extends BranchInstruction implements StackConsumer { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + IfInstruction() { + } + + + /** + * @param opcode opcode of instruction + * @param target Target instruction to branch to + */ + protected IfInstruction(short opcode, InstructionHandle target) { + super(opcode, target); + } + + + /** + * @return negation of instruction, e.g. IFEQ.negate() == IFNE + */ + public abstract IfInstruction negate(); +} diff --git a/src/org/apache/bcel/generic/IndexedInstruction.java b/src/org/apache/bcel/generic/IndexedInstruction.java new file mode 100644 index 0000000..3735f2c --- /dev/null +++ b/src/org/apache/bcel/generic/IndexedInstruction.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denote entity that refers to an index, e.g. local variable instructions, + * RET, CPInstruction, etc. + * + * @version $Id: IndexedInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface IndexedInstruction { + + public int getIndex(); + + + public void setIndex( int index ); +} diff --git a/src/org/apache/bcel/generic/Instruction.java b/src/org/apache/bcel/generic/Instruction.java new file mode 100644 index 0000000..4de3c5c --- /dev/null +++ b/src/org/apache/bcel/generic/Instruction.java @@ -0,0 +1,292 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.util.Locale; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.util.ByteSequence; + +/** + * Abstract super class for all Java byte codes. + * + * @version $Id: Instruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class Instruction implements Cloneable, Serializable { + + protected short length = 1; // Length of instruction in bytes + protected short opcode = -1; // Opcode number + private static InstructionComparator cmp = InstructionComparator.DEFAULT; + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + Instruction() { + } + + + public Instruction(short opcode, short length) { + this.length = length; + this.opcode = opcode; + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + out.writeByte(opcode); // Common for all instructions + } + + + /** @return name of instruction, i.e., opcode name + */ + public String getName() { + return Constants.OPCODE_NAMES[opcode]; + } + + + /** + * Long output format: + * + * <name of opcode> "["<opcode number>"]" + * "("<length of instruction>")" + * + * @param verbose long/short format switch + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + if (verbose) { + return getName() + "[" + opcode + "](" + length + ")"; + } else { + return getName(); + } + } + + + /** + * @return mnemonic for instruction in verbose format + */ + public String toString() { + return toString(true); + } + + + /** + * @return mnemonic for instruction with sumbolic references resolved + */ + public String toString( ConstantPool cp ) { + return toString(false); + } + + + /** + * Use with caution, since `BranchInstruction's have a `target' reference which + * is not copied correctly (only basic types are). This also applies for + * `Select' instructions with their multiple branch targets. + * + * @see BranchInstruction + * @return (shallow) copy of an instruction + */ + public Instruction copy() { + Instruction i = null; + // "Constant" instruction, no need to duplicate + if (InstructionConstants.INSTRUCTIONS[this.getOpcode()] != null) { + i = this; + } else { + try { + i = (Instruction) clone(); + } catch (CloneNotSupportedException e) { + System.err.println(e); + } + } + return i; + } + + + /** + * Read needed data (e.g. index) from file. + * + * @param bytes byte sequence to read from + * @param wide "wide" instruction flag + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + } + + + /** + * Read an instruction from (byte code) input stream and return the + * appropiate object. + * + * @param bytes input stream bytes + * @return instruction object being read + */ + public static final Instruction readInstruction( ByteSequence bytes ) throws IOException { + boolean wide = false; + short opcode = (short) bytes.readUnsignedByte(); + Instruction obj = null; + if (opcode == Constants.WIDE) { // Read next opcode after wide byte + wide = true; + opcode = (short) bytes.readUnsignedByte(); + } + if (InstructionConstants.INSTRUCTIONS[opcode] != null) { + return InstructionConstants.INSTRUCTIONS[opcode]; // Used predefined immutable object, if available + } + /* Find appropiate class, instantiate an (empty) instruction object + * and initialize it by hand. + */ + Class clazz; + try { + clazz = Class.forName(className(opcode)); + } catch (ClassNotFoundException cnfe) { + // If a class by that name does not exist, the opcode is illegal. + // Note that IMPDEP1, IMPDEP2, BREAKPOINT are also illegal in a sense. + throw new ClassGenException("Illegal opcode detected."); + } + try { + obj = (Instruction) clazz.newInstance(); + if (wide + && !((obj instanceof LocalVariableInstruction) || (obj instanceof IINC) || (obj instanceof RET))) { + throw new Exception("Illegal opcode after wide: " + opcode); + } + obj.setOpcode(opcode); + obj.initFromFile(bytes, wide); // Do further initializations, if any + // Byte code offset set in InstructionList + } catch (Exception e) { + throw new ClassGenException(e.toString()); + } + return obj; + } + + + private static final String className( short opcode ) { + String name = Constants.OPCODE_NAMES[opcode].toUpperCase(Locale.ENGLISH); + /* ICONST_0, etc. will be shortened to ICONST, etc., since ICONST_0 and the like + * are not implemented (directly). + */ + try { + int len = name.length(); + char ch1 = name.charAt(len - 2), ch2 = name.charAt(len - 1); + if ((ch1 == '_') && (ch2 >= '0') && (ch2 <= '5')) { + name = name.substring(0, len - 2); + } + if (name.equals("ICONST_M1")) { + name = "ICONST"; + } + } catch (StringIndexOutOfBoundsException e) { + System.err.println(e); + } + return "org.apache.bcel.generic." + name; + } + + + /** + * This method also gives right results for instructions whose + * effect on the stack depends on the constant pool entry they + * reference. + * @return Number of words consumed from stack by this instruction, + * or Constants.UNPREDICTABLE, if this can not be computed statically + */ + public int consumeStack( ConstantPoolGen cpg ) { + return Constants.CONSUME_STACK[opcode]; + } + + + /** + * This method also gives right results for instructions whose + * effect on the stack depends on the constant pool entry they + * reference. + * @return Number of words produced onto stack by this instruction, + * or Constants.UNPREDICTABLE, if this can not be computed statically + */ + public int produceStack( ConstantPoolGen cpg ) { + return Constants.PRODUCE_STACK[opcode]; + } + + + /** + * @return this instructions opcode + */ + public short getOpcode() { + return opcode; + } + + + /** + * @return length (in bytes) of instruction + */ + public int getLength() { + return length; + } + + + /** + * Needed in readInstruction. + */ + private void setOpcode( short opcode ) { + this.opcode = opcode; + } + + + /** Some instructions may be reused, so don't do anything by default. + */ + void dispose() { + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public abstract void accept( Visitor v ); + + + /** Get Comparator object used in the equals() method to determine + * equality of instructions. + * + * @return currently used comparator for equals() + */ + public static InstructionComparator getComparator() { + return cmp; + } + + + /** Set comparator to be used for equals(). + */ + public static void setComparator( InstructionComparator c ) { + cmp = c; + } + + + /** Check for equality, delegated to comparator + * @return true if that is an Instruction and has the same opcode + */ + public boolean equals( Object that ) { + return (that instanceof Instruction) ? cmp.equals(this, (Instruction) that) : false; + } +} diff --git a/src/org/apache/bcel/generic/InstructionComparator.java b/src/org/apache/bcel/generic/InstructionComparator.java new file mode 100644 index 0000000..0813011 --- /dev/null +++ b/src/org/apache/bcel/generic/InstructionComparator.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Equality of instructions isn't clearly to be defined. You might + * wish, for example, to compare whether instructions have the same + * meaning. E.g., whether two INVOKEVIRTUALs describe the same + * call.
      The DEFAULT comparator however, considers two instructions + * to be equal if they have same opcode and point to the same indexes + * (if any) in the constant pool or the same local variable index. Branch + * instructions must have the same target. + * + * @see Instruction + * @version $Id: InstructionComparator.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface InstructionComparator { + + public static final InstructionComparator DEFAULT = new InstructionComparator() { + + public boolean equals( Instruction i1, Instruction i2 ) { + if (i1.opcode == i2.opcode) { + if (i1 instanceof Select) { + InstructionHandle[] t1 = ((Select) i1).getTargets(); + InstructionHandle[] t2 = ((Select) i2).getTargets(); + if (t1.length == t2.length) { + for (int i = 0; i < t1.length; i++) { + if (t1[i] != t2[i]) { + return false; + } + } + return true; + } + } else if (i1 instanceof BranchInstruction) { + return ((BranchInstruction) i1).target == ((BranchInstruction) i2).target; + } else if (i1 instanceof ConstantPushInstruction) { + return ((ConstantPushInstruction) i1).getValue().equals( + ((ConstantPushInstruction) i2).getValue()); + } else if (i1 instanceof IndexedInstruction) { + return ((IndexedInstruction) i1).getIndex() == ((IndexedInstruction) i2) + .getIndex(); + } else if (i1 instanceof NEWARRAY) { + return ((NEWARRAY) i1).getTypecode() == ((NEWARRAY) i2).getTypecode(); + } else { + return true; + } + } + return false; + } + }; + + + public boolean equals( Instruction i1, Instruction i2 ); +} diff --git a/src/org/apache/bcel/generic/InstructionConstants.java b/src/org/apache/bcel/generic/InstructionConstants.java new file mode 100644 index 0000000..38846bf --- /dev/null +++ b/src/org/apache/bcel/generic/InstructionConstants.java @@ -0,0 +1,286 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; + +/** + * This interface contains shareable instruction objects. + * + * In order to save memory you can use some instructions multiply, + * since they have an immutable state and are directly derived from + * Instruction. I.e. they have no instance fields that could be + * changed. Since some of these instructions like ICONST_0 occur + * very frequently this can save a lot of time and space. This + * feature is an adaptation of the FlyWeight design pattern, we + * just use an array instead of a factory. + * + * The Instructions can also accessed directly under their names, so + * it's possible to write il.append(Instruction.ICONST_0); + * + * @version $Id: InstructionConstants.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface InstructionConstants { + + /** Predefined instruction objects + */ + public static final Instruction NOP = new NOP(); + public static final Instruction ACONST_NULL = new ACONST_NULL(); + public static final Instruction ICONST_M1 = new ICONST(-1); + public static final Instruction ICONST_0 = new ICONST(0); + public static final Instruction ICONST_1 = new ICONST(1); + public static final Instruction ICONST_2 = new ICONST(2); + public static final Instruction ICONST_3 = new ICONST(3); + public static final Instruction ICONST_4 = new ICONST(4); + public static final Instruction ICONST_5 = new ICONST(5); + public static final Instruction LCONST_0 = new LCONST(0); + public static final Instruction LCONST_1 = new LCONST(1); + public static final Instruction FCONST_0 = new FCONST(0); + public static final Instruction FCONST_1 = new FCONST(1); + public static final Instruction FCONST_2 = new FCONST(2); + public static final Instruction DCONST_0 = new DCONST(0); + public static final Instruction DCONST_1 = new DCONST(1); + public static final ArrayInstruction IALOAD = new IALOAD(); + public static final ArrayInstruction LALOAD = new LALOAD(); + public static final ArrayInstruction FALOAD = new FALOAD(); + public static final ArrayInstruction DALOAD = new DALOAD(); + public static final ArrayInstruction AALOAD = new AALOAD(); + public static final ArrayInstruction BALOAD = new BALOAD(); + public static final ArrayInstruction CALOAD = new CALOAD(); + public static final ArrayInstruction SALOAD = new SALOAD(); + public static final ArrayInstruction IASTORE = new IASTORE(); + public static final ArrayInstruction LASTORE = new LASTORE(); + public static final ArrayInstruction FASTORE = new FASTORE(); + public static final ArrayInstruction DASTORE = new DASTORE(); + public static final ArrayInstruction AASTORE = new AASTORE(); + public static final ArrayInstruction BASTORE = new BASTORE(); + public static final ArrayInstruction CASTORE = new CASTORE(); + public static final ArrayInstruction SASTORE = new SASTORE(); + public static final StackInstruction POP = new POP(); + public static final StackInstruction POP2 = new POP2(); + public static final StackInstruction DUP = new DUP(); + public static final StackInstruction DUP_X1 = new DUP_X1(); + public static final StackInstruction DUP_X2 = new DUP_X2(); + public static final StackInstruction DUP2 = new DUP2(); + public static final StackInstruction DUP2_X1 = new DUP2_X1(); + public static final StackInstruction DUP2_X2 = new DUP2_X2(); + public static final StackInstruction SWAP = new SWAP(); + public static final ArithmeticInstruction IADD = new IADD(); + public static final ArithmeticInstruction LADD = new LADD(); + public static final ArithmeticInstruction FADD = new FADD(); + public static final ArithmeticInstruction DADD = new DADD(); + public static final ArithmeticInstruction ISUB = new ISUB(); + public static final ArithmeticInstruction LSUB = new LSUB(); + public static final ArithmeticInstruction FSUB = new FSUB(); + public static final ArithmeticInstruction DSUB = new DSUB(); + public static final ArithmeticInstruction IMUL = new IMUL(); + public static final ArithmeticInstruction LMUL = new LMUL(); + public static final ArithmeticInstruction FMUL = new FMUL(); + public static final ArithmeticInstruction DMUL = new DMUL(); + public static final ArithmeticInstruction IDIV = new IDIV(); + public static final ArithmeticInstruction LDIV = new LDIV(); + public static final ArithmeticInstruction FDIV = new FDIV(); + public static final ArithmeticInstruction DDIV = new DDIV(); + public static final ArithmeticInstruction IREM = new IREM(); + public static final ArithmeticInstruction LREM = new LREM(); + public static final ArithmeticInstruction FREM = new FREM(); + public static final ArithmeticInstruction DREM = new DREM(); + public static final ArithmeticInstruction INEG = new INEG(); + public static final ArithmeticInstruction LNEG = new LNEG(); + public static final ArithmeticInstruction FNEG = new FNEG(); + public static final ArithmeticInstruction DNEG = new DNEG(); + public static final ArithmeticInstruction ISHL = new ISHL(); + public static final ArithmeticInstruction LSHL = new LSHL(); + public static final ArithmeticInstruction ISHR = new ISHR(); + public static final ArithmeticInstruction LSHR = new LSHR(); + public static final ArithmeticInstruction IUSHR = new IUSHR(); + public static final ArithmeticInstruction LUSHR = new LUSHR(); + public static final ArithmeticInstruction IAND = new IAND(); + public static final ArithmeticInstruction LAND = new LAND(); + public static final ArithmeticInstruction IOR = new IOR(); + public static final ArithmeticInstruction LOR = new LOR(); + public static final ArithmeticInstruction IXOR = new IXOR(); + public static final ArithmeticInstruction LXOR = new LXOR(); + public static final ConversionInstruction I2L = new I2L(); + public static final ConversionInstruction I2F = new I2F(); + public static final ConversionInstruction I2D = new I2D(); + public static final ConversionInstruction L2I = new L2I(); + public static final ConversionInstruction L2F = new L2F(); + public static final ConversionInstruction L2D = new L2D(); + public static final ConversionInstruction F2I = new F2I(); + public static final ConversionInstruction F2L = new F2L(); + public static final ConversionInstruction F2D = new F2D(); + public static final ConversionInstruction D2I = new D2I(); + public static final ConversionInstruction D2L = new D2L(); + public static final ConversionInstruction D2F = new D2F(); + public static final ConversionInstruction I2B = new I2B(); + public static final ConversionInstruction I2C = new I2C(); + public static final ConversionInstruction I2S = new I2S(); + public static final Instruction LCMP = new LCMP(); + public static final Instruction FCMPL = new FCMPL(); + public static final Instruction FCMPG = new FCMPG(); + public static final Instruction DCMPL = new DCMPL(); + public static final Instruction DCMPG = new DCMPG(); + public static final ReturnInstruction IRETURN = new IRETURN(); + public static final ReturnInstruction LRETURN = new LRETURN(); + public static final ReturnInstruction FRETURN = new FRETURN(); + public static final ReturnInstruction DRETURN = new DRETURN(); + public static final ReturnInstruction ARETURN = new ARETURN(); + public static final ReturnInstruction RETURN = new RETURN(); + public static final Instruction ARRAYLENGTH = new ARRAYLENGTH(); + public static final Instruction ATHROW = new ATHROW(); + public static final Instruction MONITORENTER = new MONITORENTER(); + public static final Instruction MONITOREXIT = new MONITOREXIT(); + /** You can use these constants in multiple places safely, if you can guarantee + * that you will never alter their internal values, e.g. call setIndex(). + */ + public static final LocalVariableInstruction THIS = new ALOAD(0); + public static final LocalVariableInstruction ALOAD_0 = THIS; + public static final LocalVariableInstruction ALOAD_1 = new ALOAD(1); + public static final LocalVariableInstruction ALOAD_2 = new ALOAD(2); + public static final LocalVariableInstruction ILOAD_0 = new ILOAD(0); + public static final LocalVariableInstruction ILOAD_1 = new ILOAD(1); + public static final LocalVariableInstruction ILOAD_2 = new ILOAD(2); + public static final LocalVariableInstruction ASTORE_0 = new ASTORE(0); + public static final LocalVariableInstruction ASTORE_1 = new ASTORE(1); + public static final LocalVariableInstruction ASTORE_2 = new ASTORE(2); + public static final LocalVariableInstruction ISTORE_0 = new ISTORE(0); + public static final LocalVariableInstruction ISTORE_1 = new ISTORE(1); + public static final LocalVariableInstruction ISTORE_2 = new ISTORE(2); + /** Get object via its opcode, for immutable instructions like + * branch instructions entries are set to null. + */ + public static final Instruction[] INSTRUCTIONS = new Instruction[256]; + /** Interfaces may have no static initializers, so we simulate this + * with an inner class. + */ + static final Clinit bla = new Clinit(); + + static class Clinit { + + Clinit() { + INSTRUCTIONS[Constants.NOP] = NOP; + INSTRUCTIONS[Constants.ACONST_NULL] = ACONST_NULL; + INSTRUCTIONS[Constants.ICONST_M1] = ICONST_M1; + INSTRUCTIONS[Constants.ICONST_0] = ICONST_0; + INSTRUCTIONS[Constants.ICONST_1] = ICONST_1; + INSTRUCTIONS[Constants.ICONST_2] = ICONST_2; + INSTRUCTIONS[Constants.ICONST_3] = ICONST_3; + INSTRUCTIONS[Constants.ICONST_4] = ICONST_4; + INSTRUCTIONS[Constants.ICONST_5] = ICONST_5; + INSTRUCTIONS[Constants.LCONST_0] = LCONST_0; + INSTRUCTIONS[Constants.LCONST_1] = LCONST_1; + INSTRUCTIONS[Constants.FCONST_0] = FCONST_0; + INSTRUCTIONS[Constants.FCONST_1] = FCONST_1; + INSTRUCTIONS[Constants.FCONST_2] = FCONST_2; + INSTRUCTIONS[Constants.DCONST_0] = DCONST_0; + INSTRUCTIONS[Constants.DCONST_1] = DCONST_1; + INSTRUCTIONS[Constants.IALOAD] = IALOAD; + INSTRUCTIONS[Constants.LALOAD] = LALOAD; + INSTRUCTIONS[Constants.FALOAD] = FALOAD; + INSTRUCTIONS[Constants.DALOAD] = DALOAD; + INSTRUCTIONS[Constants.AALOAD] = AALOAD; + INSTRUCTIONS[Constants.BALOAD] = BALOAD; + INSTRUCTIONS[Constants.CALOAD] = CALOAD; + INSTRUCTIONS[Constants.SALOAD] = SALOAD; + INSTRUCTIONS[Constants.IASTORE] = IASTORE; + INSTRUCTIONS[Constants.LASTORE] = LASTORE; + INSTRUCTIONS[Constants.FASTORE] = FASTORE; + INSTRUCTIONS[Constants.DASTORE] = DASTORE; + INSTRUCTIONS[Constants.AASTORE] = AASTORE; + INSTRUCTIONS[Constants.BASTORE] = BASTORE; + INSTRUCTIONS[Constants.CASTORE] = CASTORE; + INSTRUCTIONS[Constants.SASTORE] = SASTORE; + INSTRUCTIONS[Constants.POP] = POP; + INSTRUCTIONS[Constants.POP2] = POP2; + INSTRUCTIONS[Constants.DUP] = DUP; + INSTRUCTIONS[Constants.DUP_X1] = DUP_X1; + INSTRUCTIONS[Constants.DUP_X2] = DUP_X2; + INSTRUCTIONS[Constants.DUP2] = DUP2; + INSTRUCTIONS[Constants.DUP2_X1] = DUP2_X1; + INSTRUCTIONS[Constants.DUP2_X2] = DUP2_X2; + INSTRUCTIONS[Constants.SWAP] = SWAP; + INSTRUCTIONS[Constants.IADD] = IADD; + INSTRUCTIONS[Constants.LADD] = LADD; + INSTRUCTIONS[Constants.FADD] = FADD; + INSTRUCTIONS[Constants.DADD] = DADD; + INSTRUCTIONS[Constants.ISUB] = ISUB; + INSTRUCTIONS[Constants.LSUB] = LSUB; + INSTRUCTIONS[Constants.FSUB] = FSUB; + INSTRUCTIONS[Constants.DSUB] = DSUB; + INSTRUCTIONS[Constants.IMUL] = IMUL; + INSTRUCTIONS[Constants.LMUL] = LMUL; + INSTRUCTIONS[Constants.FMUL] = FMUL; + INSTRUCTIONS[Constants.DMUL] = DMUL; + INSTRUCTIONS[Constants.IDIV] = IDIV; + INSTRUCTIONS[Constants.LDIV] = LDIV; + INSTRUCTIONS[Constants.FDIV] = FDIV; + INSTRUCTIONS[Constants.DDIV] = DDIV; + INSTRUCTIONS[Constants.IREM] = IREM; + INSTRUCTIONS[Constants.LREM] = LREM; + INSTRUCTIONS[Constants.FREM] = FREM; + INSTRUCTIONS[Constants.DREM] = DREM; + INSTRUCTIONS[Constants.INEG] = INEG; + INSTRUCTIONS[Constants.LNEG] = LNEG; + INSTRUCTIONS[Constants.FNEG] = FNEG; + INSTRUCTIONS[Constants.DNEG] = DNEG; + INSTRUCTIONS[Constants.ISHL] = ISHL; + INSTRUCTIONS[Constants.LSHL] = LSHL; + INSTRUCTIONS[Constants.ISHR] = ISHR; + INSTRUCTIONS[Constants.LSHR] = LSHR; + INSTRUCTIONS[Constants.IUSHR] = IUSHR; + INSTRUCTIONS[Constants.LUSHR] = LUSHR; + INSTRUCTIONS[Constants.IAND] = IAND; + INSTRUCTIONS[Constants.LAND] = LAND; + INSTRUCTIONS[Constants.IOR] = IOR; + INSTRUCTIONS[Constants.LOR] = LOR; + INSTRUCTIONS[Constants.IXOR] = IXOR; + INSTRUCTIONS[Constants.LXOR] = LXOR; + INSTRUCTIONS[Constants.I2L] = I2L; + INSTRUCTIONS[Constants.I2F] = I2F; + INSTRUCTIONS[Constants.I2D] = I2D; + INSTRUCTIONS[Constants.L2I] = L2I; + INSTRUCTIONS[Constants.L2F] = L2F; + INSTRUCTIONS[Constants.L2D] = L2D; + INSTRUCTIONS[Constants.F2I] = F2I; + INSTRUCTIONS[Constants.F2L] = F2L; + INSTRUCTIONS[Constants.F2D] = F2D; + INSTRUCTIONS[Constants.D2I] = D2I; + INSTRUCTIONS[Constants.D2L] = D2L; + INSTRUCTIONS[Constants.D2F] = D2F; + INSTRUCTIONS[Constants.I2B] = I2B; + INSTRUCTIONS[Constants.I2C] = I2C; + INSTRUCTIONS[Constants.I2S] = I2S; + INSTRUCTIONS[Constants.LCMP] = LCMP; + INSTRUCTIONS[Constants.FCMPL] = FCMPL; + INSTRUCTIONS[Constants.FCMPG] = FCMPG; + INSTRUCTIONS[Constants.DCMPL] = DCMPL; + INSTRUCTIONS[Constants.DCMPG] = DCMPG; + INSTRUCTIONS[Constants.IRETURN] = IRETURN; + INSTRUCTIONS[Constants.LRETURN] = LRETURN; + INSTRUCTIONS[Constants.FRETURN] = FRETURN; + INSTRUCTIONS[Constants.DRETURN] = DRETURN; + INSTRUCTIONS[Constants.ARETURN] = ARETURN; + INSTRUCTIONS[Constants.RETURN] = RETURN; + INSTRUCTIONS[Constants.ARRAYLENGTH] = ARRAYLENGTH; + INSTRUCTIONS[Constants.ATHROW] = ATHROW; + INSTRUCTIONS[Constants.MONITORENTER] = MONITORENTER; + INSTRUCTIONS[Constants.MONITOREXIT] = MONITOREXIT; + } + } +} diff --git a/src/org/apache/bcel/generic/InstructionFactory.java b/src/org/apache/bcel/generic/InstructionFactory.java new file mode 100644 index 0000000..54d4304 --- /dev/null +++ b/src/org/apache/bcel/generic/InstructionFactory.java @@ -0,0 +1,743 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; + +/** + * Instances of this class may be used, e.g., to generate typed + * versions of instructions. Its main purpose is to be used as the + * byte code generating backend of a compiler. You can subclass it to + * add your own create methods. + * + * @version $Id: InstructionFactory.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Constants + */ +public class InstructionFactory implements InstructionConstants, java.io.Serializable { + + protected ClassGen cg; + protected ConstantPoolGen cp; + + + public InstructionFactory(ClassGen cg, ConstantPoolGen cp) { + this.cg = cg; + this.cp = cp; + } + + + /** Initialize with ClassGen object + */ + public InstructionFactory(ClassGen cg) { + this(cg, cg.getConstantPool()); + } + + + /** Initialize just with ConstantPoolGen object + */ + public InstructionFactory(ConstantPoolGen cp) { + this(null, cp); + } + + + /** Create an invoke instruction. + * + * @param class_name name of the called class + * @param name name of the called method + * @param ret_type return type of method + * @param arg_types argument types of method + * @param kind how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, + * or INVOKESPECIAL + * @see Constants + */ + public InvokeInstruction createInvoke( String class_name, String name, Type ret_type, + Type[] arg_types, short kind ) { + int index; + int nargs = 0; + String signature = Type.getMethodSignature(ret_type, arg_types); + for (int i = 0; i < arg_types.length; i++) { + nargs += arg_types[i].getSize(); + } + if (kind == Constants.INVOKEINTERFACE) { + index = cp.addInterfaceMethodref(class_name, name, signature); + } else { + index = cp.addMethodref(class_name, name, signature); + } + switch (kind) { + case Constants.INVOKESPECIAL: + return new INVOKESPECIAL(index); + case Constants.INVOKEVIRTUAL: + return new INVOKEVIRTUAL(index); + case Constants.INVOKESTATIC: + return new INVOKESTATIC(index); + case Constants.INVOKEINTERFACE: + return new INVOKEINTERFACE(index, nargs + 1); + default: + throw new RuntimeException("Oops: Unknown invoke kind:" + kind); + } + } + + + /** Create a call to the most popular System.out.println() method. + * + * @param s the string to print + */ + public InstructionList createPrintln( String s ) { + InstructionList il = new InstructionList(); + int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;"); + int println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V"); + il.append(new GETSTATIC(out)); + il.append(new PUSH(cp, s)); + il.append(new INVOKEVIRTUAL(println)); + return il; + } + + + /** Uses PUSH to push a constant value onto the stack. + * @param value must be of type Number, Boolean, Character or String + */ + public Instruction createConstant( Object value ) { + PUSH push; + if (value instanceof Number) { + push = new PUSH(cp, (Number) value); + } else if (value instanceof String) { + push = new PUSH(cp, (String) value); + } else if (value instanceof Boolean) { + push = new PUSH(cp, (Boolean) value); + } else if (value instanceof Character) { + push = new PUSH(cp, (Character) value); + } else { + throw new ClassGenException("Illegal type: " + value.getClass()); + } + return push.getInstruction(); + } + + private static class MethodObject { + + Type[] arg_types; + Type result_type; + String class_name; + String name; + int access; + + + MethodObject(String c, String n, Type r, Type[] a, int acc) { + class_name = c; + name = n; + result_type = r; + arg_types = a; + access = acc; + } + } + + + private InvokeInstruction createInvoke( MethodObject m, short kind ) { + return createInvoke(m.class_name, m.name, m.result_type, m.arg_types, kind); + } + + private static MethodObject[] append_mos = { + new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { + Type.STRING + }, Constants.ACC_PUBLIC), + new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { + Type.OBJECT + }, Constants.ACC_PUBLIC), + null, + null, // indices 2, 3 + new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { + Type.BOOLEAN + }, Constants.ACC_PUBLIC), + new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { + Type.CHAR + }, Constants.ACC_PUBLIC), + new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { + Type.FLOAT + }, Constants.ACC_PUBLIC), + new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { + Type.DOUBLE + }, Constants.ACC_PUBLIC), + new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { + Type.INT + }, Constants.ACC_PUBLIC), + new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(byte) + new Type[] { + Type.INT + }, Constants.ACC_PUBLIC), + new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(short) + new Type[] { + Type.INT + }, Constants.ACC_PUBLIC), + new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { + Type.LONG + }, Constants.ACC_PUBLIC) + }; + + + private static final boolean isString( Type type ) { + return ((type instanceof ObjectType) && ((ObjectType) type).getClassName().equals( + "java.lang.String")); + } + + + public Instruction createAppend( Type type ) { + byte t = type.getType(); + if (isString(type)) { + return createInvoke(append_mos[0], Constants.INVOKEVIRTUAL); + } + switch (t) { + case Constants.T_BOOLEAN: + case Constants.T_CHAR: + case Constants.T_FLOAT: + case Constants.T_DOUBLE: + case Constants.T_BYTE: + case Constants.T_SHORT: + case Constants.T_INT: + case Constants.T_LONG: + return createInvoke(append_mos[t], Constants.INVOKEVIRTUAL); + case Constants.T_ARRAY: + case Constants.T_OBJECT: + return createInvoke(append_mos[1], Constants.INVOKEVIRTUAL); + default: + throw new RuntimeException("Oops: No append for this type? " + type); + } + } + + + /** Create a field instruction. + * + * @param class_name name of the accessed class + * @param name name of the referenced field + * @param type type of field + * @param kind how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC + * @see Constants + */ + public FieldInstruction createFieldAccess( String class_name, String name, Type type, short kind ) { + int index; + String signature = type.getSignature(); + index = cp.addFieldref(class_name, name, signature); + switch (kind) { + case Constants.GETFIELD: + return new GETFIELD(index); + case Constants.PUTFIELD: + return new PUTFIELD(index); + case Constants.GETSTATIC: + return new GETSTATIC(index); + case Constants.PUTSTATIC: + return new PUTSTATIC(index); + default: + throw new RuntimeException("Oops: Unknown getfield kind:" + kind); + } + } + + + /** Create reference to `this' + */ + public static Instruction createThis() { + return new ALOAD(0); + } + + + /** Create typed return + */ + public static ReturnInstruction createReturn( Type type ) { + switch (type.getType()) { + case Constants.T_ARRAY: + case Constants.T_OBJECT: + return ARETURN; + case Constants.T_INT: + case Constants.T_SHORT: + case Constants.T_BOOLEAN: + case Constants.T_CHAR: + case Constants.T_BYTE: + return IRETURN; + case Constants.T_FLOAT: + return FRETURN; + case Constants.T_DOUBLE: + return DRETURN; + case Constants.T_LONG: + return LRETURN; + case Constants.T_VOID: + return RETURN; + default: + throw new RuntimeException("Invalid type: " + type); + } + } + + + private static final ArithmeticInstruction createBinaryIntOp( char first, String op ) { + switch (first) { + case '-': + return ISUB; + case '+': + return IADD; + case '%': + return IREM; + case '*': + return IMUL; + case '/': + return IDIV; + case '&': + return IAND; + case '|': + return IOR; + case '^': + return IXOR; + case '<': + return ISHL; + case '>': + return op.equals(">>>") + ? (ArithmeticInstruction) IUSHR + : (ArithmeticInstruction) ISHR; + default: + throw new RuntimeException("Invalid operand " + op); + } + } + + + private static final ArithmeticInstruction createBinaryLongOp( char first, String op ) { + switch (first) { + case '-': + return LSUB; + case '+': + return LADD; + case '%': + return LREM; + case '*': + return LMUL; + case '/': + return LDIV; + case '&': + return LAND; + case '|': + return LOR; + case '^': + return LXOR; + case '<': + return LSHL; + case '>': + return op.equals(">>>") + ? (ArithmeticInstruction) LUSHR + : (ArithmeticInstruction) LSHR; + default: + throw new RuntimeException("Invalid operand " + op); + } + } + + + private static final ArithmeticInstruction createBinaryFloatOp( char op ) { + switch (op) { + case '-': + return FSUB; + case '+': + return FADD; + case '*': + return FMUL; + case '/': + return FDIV; + default: + throw new RuntimeException("Invalid operand " + op); + } + } + + + private static final ArithmeticInstruction createBinaryDoubleOp( char op ) { + switch (op) { + case '-': + return DSUB; + case '+': + return DADD; + case '*': + return DMUL; + case '/': + return DDIV; + default: + throw new RuntimeException("Invalid operand " + op); + } + } + + + /** + * Create binary operation for simple basic types, such as int and float. + * + * @param op operation, such as "+", "*", "<<", etc. + */ + public static ArithmeticInstruction createBinaryOperation( String op, Type type ) { + char first = op.toCharArray()[0]; + switch (type.getType()) { + case Constants.T_BYTE: + case Constants.T_SHORT: + case Constants.T_INT: + case Constants.T_CHAR: + return createBinaryIntOp(first, op); + case Constants.T_LONG: + return createBinaryLongOp(first, op); + case Constants.T_FLOAT: + return createBinaryFloatOp(first); + case Constants.T_DOUBLE: + return createBinaryDoubleOp(first); + default: + throw new RuntimeException("Invalid type " + type); + } + } + + + /** + * @param size size of operand, either 1 (int, e.g.) or 2 (double) + */ + public static StackInstruction createPop( int size ) { + return (size == 2) ? (StackInstruction) POP2 : (StackInstruction) POP; + } + + + /** + * @param size size of operand, either 1 (int, e.g.) or 2 (double) + */ + public static StackInstruction createDup( int size ) { + return (size == 2) ? (StackInstruction) DUP2 : (StackInstruction) DUP; + } + + + /** + * @param size size of operand, either 1 (int, e.g.) or 2 (double) + */ + public static StackInstruction createDup_2( int size ) { + return (size == 2) ? (StackInstruction) DUP2_X2 : (StackInstruction) DUP_X2; + } + + + /** + * @param size size of operand, either 1 (int, e.g.) or 2 (double) + */ + public static StackInstruction createDup_1( int size ) { + return (size == 2) ? (StackInstruction) DUP2_X1 : (StackInstruction) DUP_X1; + } + + + /** + * @param index index of local variable + */ + public static LocalVariableInstruction createStore( Type type, int index ) { + switch (type.getType()) { + case Constants.T_BOOLEAN: + case Constants.T_CHAR: + case Constants.T_BYTE: + case Constants.T_SHORT: + case Constants.T_INT: + return new ISTORE(index); + case Constants.T_FLOAT: + return new FSTORE(index); + case Constants.T_DOUBLE: + return new DSTORE(index); + case Constants.T_LONG: + return new LSTORE(index); + case Constants.T_ARRAY: + case Constants.T_OBJECT: + return new ASTORE(index); + default: + throw new RuntimeException("Invalid type " + type); + } + } + + + /** + * @param index index of local variable + */ + public static LocalVariableInstruction createLoad( Type type, int index ) { + switch (type.getType()) { + case Constants.T_BOOLEAN: + case Constants.T_CHAR: + case Constants.T_BYTE: + case Constants.T_SHORT: + case Constants.T_INT: + return new ILOAD(index); + case Constants.T_FLOAT: + return new FLOAD(index); + case Constants.T_DOUBLE: + return new DLOAD(index); + case Constants.T_LONG: + return new LLOAD(index); + case Constants.T_ARRAY: + case Constants.T_OBJECT: + return new ALOAD(index); + default: + throw new RuntimeException("Invalid type " + type); + } + } + + + /** + * @param type type of elements of array, i.e., array.getElementType() + */ + public static ArrayInstruction createArrayLoad( Type type ) { + switch (type.getType()) { + case Constants.T_BOOLEAN: + case Constants.T_BYTE: + return BALOAD; + case Constants.T_CHAR: + return CALOAD; + case Constants.T_SHORT: + return SALOAD; + case Constants.T_INT: + return IALOAD; + case Constants.T_FLOAT: + return FALOAD; + case Constants.T_DOUBLE: + return DALOAD; + case Constants.T_LONG: + return LALOAD; + case Constants.T_ARRAY: + case Constants.T_OBJECT: + return AALOAD; + default: + throw new RuntimeException("Invalid type " + type); + } + } + + + /** + * @param type type of elements of array, i.e., array.getElementType() + */ + public static ArrayInstruction createArrayStore( Type type ) { + switch (type.getType()) { + case Constants.T_BOOLEAN: + case Constants.T_BYTE: + return BASTORE; + case Constants.T_CHAR: + return CASTORE; + case Constants.T_SHORT: + return SASTORE; + case Constants.T_INT: + return IASTORE; + case Constants.T_FLOAT: + return FASTORE; + case Constants.T_DOUBLE: + return DASTORE; + case Constants.T_LONG: + return LASTORE; + case Constants.T_ARRAY: + case Constants.T_OBJECT: + return AASTORE; + default: + throw new RuntimeException("Invalid type " + type); + } + } + + + /** Create conversion operation for two stack operands, this may be an I2C, instruction, e.g., + * if the operands are basic types and CHECKCAST if they are reference types. + */ + public Instruction createCast( Type src_type, Type dest_type ) { + if ((src_type instanceof BasicType) && (dest_type instanceof BasicType)) { + byte dest = dest_type.getType(); + byte src = src_type.getType(); + if (dest == Constants.T_LONG + && (src == Constants.T_CHAR || src == Constants.T_BYTE || src == Constants.T_SHORT)) { + src = Constants.T_INT; + } + String[] short_names = { + "C", "F", "D", "B", "S", "I", "L" + }; + String name = "org.apache.bcel.generic." + short_names[src - Constants.T_CHAR] + "2" + + short_names[dest - Constants.T_CHAR]; + Instruction i = null; + try { + i = (Instruction) java.lang.Class.forName(name).newInstance(); + } catch (Exception e) { + throw new RuntimeException("Could not find instruction: " + name); + } + return i; + } else if ((src_type instanceof ReferenceType) && (dest_type instanceof ReferenceType)) { + if (dest_type instanceof ArrayType) { + return new CHECKCAST(cp.addArrayClass((ArrayType) dest_type)); + } else { + return new CHECKCAST(cp.addClass(((ObjectType) dest_type).getClassName())); + } + } else { + throw new RuntimeException("Can not cast " + src_type + " to " + dest_type); + } + } + + + public GETFIELD createGetField( String class_name, String name, Type t ) { + return new GETFIELD(cp.addFieldref(class_name, name, t.getSignature())); + } + + + public GETSTATIC createGetStatic( String class_name, String name, Type t ) { + return new GETSTATIC(cp.addFieldref(class_name, name, t.getSignature())); + } + + + public PUTFIELD createPutField( String class_name, String name, Type t ) { + return new PUTFIELD(cp.addFieldref(class_name, name, t.getSignature())); + } + + + public PUTSTATIC createPutStatic( String class_name, String name, Type t ) { + return new PUTSTATIC(cp.addFieldref(class_name, name, t.getSignature())); + } + + + public CHECKCAST createCheckCast( ReferenceType t ) { + if (t instanceof ArrayType) { + return new CHECKCAST(cp.addArrayClass((ArrayType) t)); + } else { + return new CHECKCAST(cp.addClass((ObjectType) t)); + } + } + + + public INSTANCEOF createInstanceOf( ReferenceType t ) { + if (t instanceof ArrayType) { + return new INSTANCEOF(cp.addArrayClass((ArrayType) t)); + } else { + return new INSTANCEOF(cp.addClass((ObjectType) t)); + } + } + + + public NEW createNew( ObjectType t ) { + return new NEW(cp.addClass(t)); + } + + + public NEW createNew( String s ) { + return createNew(new ObjectType(s)); + } + + + /** Create new array of given size and type. + * @return an instruction that creates the corresponding array at runtime, i.e. is an AllocationInstruction + */ + public Instruction createNewArray( Type t, short dim ) { + if (dim == 1) { + if (t instanceof ObjectType) { + return new ANEWARRAY(cp.addClass((ObjectType) t)); + } else if (t instanceof ArrayType) { + return new ANEWARRAY(cp.addArrayClass((ArrayType) t)); + } else { + return new NEWARRAY(((BasicType) t).getType()); + } + } else { + ArrayType at; + if (t instanceof ArrayType) { + at = (ArrayType) t; + } else { + at = new ArrayType(t, dim); + } + return new MULTIANEWARRAY(cp.addArrayClass(at), dim); + } + } + + + /** Create "null" value for reference types, 0 for basic types like int + */ + public static Instruction createNull( Type type ) { + switch (type.getType()) { + case Constants.T_ARRAY: + case Constants.T_OBJECT: + return ACONST_NULL; + case Constants.T_INT: + case Constants.T_SHORT: + case Constants.T_BOOLEAN: + case Constants.T_CHAR: + case Constants.T_BYTE: + return ICONST_0; + case Constants.T_FLOAT: + return FCONST_0; + case Constants.T_DOUBLE: + return DCONST_0; + case Constants.T_LONG: + return LCONST_0; + case Constants.T_VOID: + return NOP; + default: + throw new RuntimeException("Invalid type: " + type); + } + } + + + /** Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH. + * For those you should use the SWITCH compound instruction. + */ + public static BranchInstruction createBranchInstruction( short opcode, InstructionHandle target ) { + switch (opcode) { + case Constants.IFEQ: + return new IFEQ(target); + case Constants.IFNE: + return new IFNE(target); + case Constants.IFLT: + return new IFLT(target); + case Constants.IFGE: + return new IFGE(target); + case Constants.IFGT: + return new IFGT(target); + case Constants.IFLE: + return new IFLE(target); + case Constants.IF_ICMPEQ: + return new IF_ICMPEQ(target); + case Constants.IF_ICMPNE: + return new IF_ICMPNE(target); + case Constants.IF_ICMPLT: + return new IF_ICMPLT(target); + case Constants.IF_ICMPGE: + return new IF_ICMPGE(target); + case Constants.IF_ICMPGT: + return new IF_ICMPGT(target); + case Constants.IF_ICMPLE: + return new IF_ICMPLE(target); + case Constants.IF_ACMPEQ: + return new IF_ACMPEQ(target); + case Constants.IF_ACMPNE: + return new IF_ACMPNE(target); + case Constants.GOTO: + return new GOTO(target); + case Constants.JSR: + return new JSR(target); + case Constants.IFNULL: + return new IFNULL(target); + case Constants.IFNONNULL: + return new IFNONNULL(target); + case Constants.GOTO_W: + return new GOTO_W(target); + case Constants.JSR_W: + return new JSR_W(target); + default: + throw new RuntimeException("Invalid opcode: " + opcode); + } + } + + + public void setClassGen( ClassGen c ) { + cg = c; + } + + + public ClassGen getClassGen() { + return cg; + } + + + public void setConstantPool( ConstantPoolGen c ) { + cp = c; + } + + + public ConstantPoolGen getConstantPool() { + return cp; + } +} diff --git a/src/org/apache/bcel/generic/InstructionHandle.java b/src/org/apache/bcel/generic/InstructionHandle.java new file mode 100644 index 0000000..176b76f --- /dev/null +++ b/src/org/apache/bcel/generic/InstructionHandle.java @@ -0,0 +1,290 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.apache.bcel.classfile.Utility; + +/** + * Instances of this class give users a handle to the instructions contained in + * an InstructionList. Instruction objects may be used more than once within a + * list, this is useful because it saves memory and may be much faster. + * + * Within an InstructionList an InstructionHandle object is wrapped + * around all instructions, i.e., it implements a cell in a + * doubly-linked list. From the outside only the next and the + * previous instruction (handle) are accessible. One + * can traverse the list via an Enumeration returned by + * InstructionList.elements(). + * + * @version $Id: InstructionHandle.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Instruction + * @see BranchHandle + * @see InstructionList + */ +public class InstructionHandle implements java.io.Serializable { + + InstructionHandle next, prev; // Will be set from the outside + Instruction instruction; + protected int i_position = -1; // byte code offset of instruction + private Set targeters; + private Map attributes; + + + public final InstructionHandle getNext() { + return next; + } + + + public final InstructionHandle getPrev() { + return prev; + } + + + public final Instruction getInstruction() { + return instruction; + } + + + /** + * Replace current instruction contained in this handle. + * Old instruction is disposed using Instruction.dispose(). + */ + public void setInstruction( Instruction i ) { // Overridden in BranchHandle + if (i == null) { + throw new ClassGenException("Assigning null to handle"); + } + if ((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction)) { + throw new ClassGenException("Assigning branch instruction " + i + " to plain handle"); + } + if (instruction != null) { + instruction.dispose(); + } + instruction = i; + } + + + /** + * Temporarily swap the current instruction, without disturbing + * anything. Meant to be used by a debugger, implementing + * breakpoints. Current instruction is returned. + */ + public Instruction swapInstruction( Instruction i ) { + Instruction oldInstruction = instruction; + instruction = i; + return oldInstruction; + } + + + /*private*/protected InstructionHandle(Instruction i) { + setInstruction(i); + } + + private static InstructionHandle ih_list = null; // List of reusable handles + + + /** Factory method. + */ + static final InstructionHandle getInstructionHandle( Instruction i ) { + if (ih_list == null) { + return new InstructionHandle(i); + } else { + InstructionHandle ih = ih_list; + ih_list = ih.next; + ih.setInstruction(i); + return ih; + } + } + + + /** + * Called by InstructionList.setPositions when setting the position for every + * instruction. In the presence of variable length instructions `setPositions()' + * performs multiple passes over the instruction list to calculate the + * correct (byte) positions and offsets by calling this function. + * + * @param offset additional offset caused by preceding (variable length) instructions + * @param max_offset the maximum offset that may be caused by these instructions + * @return additional offset caused by possible change of this instruction's length + */ + protected int updatePosition( int offset, int max_offset ) { + i_position += offset; + return 0; + } + + + /** @return the position, i.e., the byte code offset of the contained + * instruction. This is accurate only after + * InstructionList.setPositions() has been called. + */ + public int getPosition() { + return i_position; + } + + + /** Set the position, i.e., the byte code offset of the contained + * instruction. + */ + void setPosition( int pos ) { + i_position = pos; + } + + + /** Overridden in BranchHandle + */ + protected void addHandle() { + next = ih_list; + ih_list = this; + } + + + /** + * Delete contents, i.e., remove user access and make handle reusable. + */ + void dispose() { + next = prev = null; + instruction.dispose(); + instruction = null; + i_position = -1; + attributes = null; + removeAllTargeters(); + addHandle(); + } + + + /** Remove all targeters, if any. + */ + public void removeAllTargeters() { + if (targeters != null) { + targeters.clear(); + } + } + + + /** + * Denote this handle isn't referenced anymore by t. + */ + public void removeTargeter( InstructionTargeter t ) { + if (targeters != null) { + targeters.remove(t); + } + } + + + /** + * Denote this handle is being referenced by t. + */ + public void addTargeter( InstructionTargeter t ) { + if (targeters == null) { + targeters = new HashSet(); + } + //if(!targeters.contains(t)) + targeters.add(t); + } + + + public boolean hasTargeters() { + return (targeters != null) && (targeters.size() > 0); + } + + + /** + * @return null, if there are no targeters + */ + public InstructionTargeter[] getTargeters() { + if (!hasTargeters()) { + return null; + } + InstructionTargeter[] t = new InstructionTargeter[targeters.size()]; + targeters.toArray(t); + return t; + } + + + /** @return a (verbose) string representation of the contained instruction. + */ + public String toString( boolean verbose ) { + return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose); + } + + + /** @return a string representation of the contained instruction. + */ + public String toString() { + return toString(true); + } + + + /** Add an attribute to an instruction handle. + * + * @param key the key object to store/retrieve the attribute + * @param attr the attribute to associate with this handle + */ + public void addAttribute( Object key, Object attr ) { + if (attributes == null) { + attributes = new HashMap(3); + } + attributes.put(key, attr); + } + + + /** Delete an attribute of an instruction handle. + * + * @param key the key object to retrieve the attribute + */ + public void removeAttribute( Object key ) { + if (attributes != null) { + attributes.remove(key); + } + } + + + /** Get attribute of an instruction handle. + * + * @param key the key object to store/retrieve the attribute + */ + public Object getAttribute( Object key ) { + if (attributes != null) { + return attributes.get(key); + } + return null; + } + + + /** @return all attributes associated with this handle + */ + public Collection getAttributes() { + if (attributes == null) { + attributes = new HashMap(3); + } + return attributes.values(); + } + + + /** Convenience method, simply calls accept() on the contained instruction. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + instruction.accept(v); + } +} diff --git a/src/org/apache/bcel/generic/InstructionList.java b/src/org/apache/bcel/generic/InstructionList.java new file mode 100644 index 0000000..9a10664 --- /dev/null +++ b/src/org/apache/bcel/generic/InstructionList.java @@ -0,0 +1,1265 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.util.ByteSequence; + +/** + * This class is a container for a list of Instruction objects. Instructions can + * be appended, inserted, moved, deleted, etc.. Instructions are being + * wrapped into InstructionHandles objects that + * are returned upon append/insert operations. They give the user + * (read only) access to the list structure, such that it can be traversed and + * manipulated in a controlled way. + * + * A list is finally dumped to a byte code array with getByteCode. + * + * @version $Id: InstructionList.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Instruction + * @see InstructionHandle + * @see BranchHandle + */ +public class InstructionList implements Serializable { + + private InstructionHandle start = null, end = null; + private int length = 0; // number of elements in list + private int[] byte_positions; // byte code offsets corresponding to instructions + + + /** + * Create (empty) instruction list. + */ + public InstructionList() { + } + + + /** + * Create instruction list containing one instruction. + * @param i initial instruction + */ + public InstructionList(Instruction i) { + append(i); + } + + + /** + * Create instruction list containing one instruction. + * @param i initial instruction + */ + public InstructionList(BranchInstruction i) { + append(i); + } + + + /** + * Initialize list with (nonnull) compound instruction. Consumes argument + * list, i.e., it becomes empty. + * + * @param c compound instruction (list) + */ + public InstructionList(CompoundInstruction c) { + append(c.getInstructionList()); + } + + + /** + * Test for empty list. + */ + public boolean isEmpty() { + return start == null; + } // && end == null + + + /** + * Find the target instruction (handle) that corresponds to the given target + * position (byte code offset). + * + * @param ihs array of instruction handles, i.e. il.getInstructionHandles() + * @param pos array of positions corresponding to ihs, i.e. il.getInstructionPositions() + * @param count length of arrays + * @param target target position to search for + * @return target position's instruction handle if available + */ + public static InstructionHandle findHandle( InstructionHandle[] ihs, int[] pos, int count, + int target ) { + int l = 0, r = count - 1; + /* Do a binary search since the pos array is orderd. + */ + do { + int i = (l + r) / 2; + int j = pos[i]; + if (j == target) { + return ihs[i]; + } else if (target < j) { + r = i - 1; + } else { + l = i + 1; + } + } while (l <= r); + return null; + } + + + /** + * Get instruction handle for instruction at byte code position pos. + * This only works properly, if the list is freshly initialized from a byte array or + * setPositions() has been called before this method. + * + * @param pos byte code position to search for + * @return target position's instruction handle if available + */ + public InstructionHandle findHandle( int pos ) { + InstructionHandle[] ihs = getInstructionHandles(); + return findHandle(ihs, byte_positions, length, pos); + } + + + /** + * Initialize instruction list from byte array. + * + * @param code byte array containing the instructions + */ + public InstructionList(byte[] code) { + ByteSequence bytes = new ByteSequence(code); + InstructionHandle[] ihs = new InstructionHandle[code.length]; + int[] pos = new int[code.length]; // Can't be more than that + int count = 0; // Contains actual length + /* Pass 1: Create an object for each byte code and append them + * to the list. + */ + try { + while (bytes.available() > 0) { + // Remember byte offset and associate it with the instruction + int off = bytes.getIndex(); + pos[count] = off; + /* Read one instruction from the byte stream, the byte position is set + * accordingly. + */ + Instruction i = Instruction.readInstruction(bytes); + InstructionHandle ih; + if (i instanceof BranchInstruction) { + ih = append((BranchInstruction) i); + } else { + ih = append(i); + } + ih.setPosition(off); + ihs[count] = ih; + count++; + } + } catch (IOException e) { + throw new ClassGenException(e.toString()); + } + byte_positions = new int[count]; // Trim to proper size + System.arraycopy(pos, 0, byte_positions, 0, count); + /* Pass 2: Look for BranchInstruction and update their targets, i.e., + * convert offsets to instruction handles. + */ + for (int i = 0; i < count; i++) { + if (ihs[i] instanceof BranchHandle) { + BranchInstruction bi = (BranchInstruction) ihs[i].instruction; + int target = bi.position + bi.getIndex(); /* Byte code position: + * relative -> absolute. */ + // Search for target position + InstructionHandle ih = findHandle(ihs, pos, count, target); + if (ih == null) { + throw new ClassGenException("Couldn't find target for branch: " + bi); + } + bi.setTarget(ih); // Update target + // If it is a Select instruction, update all branch targets + if (bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH + Select s = (Select) bi; + int[] indices = s.getIndices(); + for (int j = 0; j < indices.length; j++) { + target = bi.position + indices[j]; + ih = findHandle(ihs, pos, count, target); + if (ih == null) { + throw new ClassGenException("Couldn't find target for switch: " + bi); + } + s.setTarget(j, ih); // Update target + } + } + } + } + } + + + /** + * Append another list after instruction (handle) ih contained in this list. + * Consumes argument list, i.e., it becomes empty. + * + * @param ih where to append the instruction list + * @param il Instruction list to append to this one + * @return instruction handle pointing to the first appended instruction + */ + public InstructionHandle append( InstructionHandle ih, InstructionList il ) { + if (il == null) { + throw new ClassGenException("Appending null InstructionList"); + } + if (il.isEmpty()) { + return ih; + } + InstructionHandle next = ih.next, ret = il.start; + ih.next = il.start; + il.start.prev = ih; + il.end.next = next; + if (next != null) { + next.prev = il.end; + } else { + end = il.end; // Update end ... + } + length += il.length; // Update length + il.clear(); + return ret; + } + + + /** + * Append another list after instruction i contained in this list. + * Consumes argument list, i.e., it becomes empty. + * + * @param i where to append the instruction list + * @param il Instruction list to append to this one + * @return instruction handle pointing to the first appended instruction + */ + public InstructionHandle append( Instruction i, InstructionList il ) { + InstructionHandle ih; + if ((ih = findInstruction2(i)) == null) { + throw new ClassGenException("Instruction " + i + " is not contained in this list."); + } + return append(ih, il); + } + + + /** + * Append another list to this one. + * Consumes argument list, i.e., it becomes empty. + * + * @param il list to append to end of this list + * @return instruction handle of the first appended instruction + */ + public InstructionHandle append( InstructionList il ) { + if (il == null) { + throw new ClassGenException("Appending null InstructionList"); + } + if (il.isEmpty()) { + return null; + } + if (isEmpty()) { + start = il.start; + end = il.end; + length = il.length; + il.clear(); + return start; + } else { + return append(end, il); // was end.instruction + } + } + + + /** + * Append an instruction to the end of this list. + * + * @param ih instruction to append + */ + private void append( InstructionHandle ih ) { + if (isEmpty()) { + start = end = ih; + ih.next = ih.prev = null; + } else { + end.next = ih; + ih.prev = end; + ih.next = null; + end = ih; + } + length++; // Update length + } + + + /** + * Append an instruction to the end of this list. + * + * @param i instruction to append + * @return instruction handle of the appended instruction + */ + public InstructionHandle append( Instruction i ) { + InstructionHandle ih = InstructionHandle.getInstructionHandle(i); + append(ih); + return ih; + } + + + /** + * Append a branch instruction to the end of this list. + * + * @param i branch instruction to append + * @return branch instruction handle of the appended instruction + */ + public BranchHandle append( BranchInstruction i ) { + BranchHandle ih = BranchHandle.getBranchHandle(i); + append(ih); + return ih; + } + + + /** + * Append a single instruction j after another instruction i, which + * must be in this list of course! + * + * @param i Instruction in list + * @param j Instruction to append after i in list + * @return instruction handle of the first appended instruction + */ + public InstructionHandle append( Instruction i, Instruction j ) { + return append(i, new InstructionList(j)); + } + + + /** + * Append a compound instruction, after instruction i. + * + * @param i Instruction in list + * @param c The composite instruction (containing an InstructionList) + * @return instruction handle of the first appended instruction + */ + public InstructionHandle append( Instruction i, CompoundInstruction c ) { + return append(i, c.getInstructionList()); + } + + + /** + * Append a compound instruction. + * + * @param c The composite instruction (containing an InstructionList) + * @return instruction handle of the first appended instruction + */ + public InstructionHandle append( CompoundInstruction c ) { + return append(c.getInstructionList()); + } + + + /** + * Append a compound instruction. + * + * @param ih where to append the instruction list + * @param c The composite instruction (containing an InstructionList) + * @return instruction handle of the first appended instruction + */ + public InstructionHandle append( InstructionHandle ih, CompoundInstruction c ) { + return append(ih, c.getInstructionList()); + } + + + /** + * Append an instruction after instruction (handle) ih contained in this list. + * + * @param ih where to append the instruction list + * @param i Instruction to append + * @return instruction handle pointing to the first appended instruction + */ + public InstructionHandle append( InstructionHandle ih, Instruction i ) { + return append(ih, new InstructionList(i)); + } + + + /** + * Append an instruction after instruction (handle) ih contained in this list. + * + * @param ih where to append the instruction list + * @param i Instruction to append + * @return instruction handle pointing to the first appended instruction + */ + public BranchHandle append( InstructionHandle ih, BranchInstruction i ) { + BranchHandle bh = BranchHandle.getBranchHandle(i); + InstructionList il = new InstructionList(); + il.append(bh); + append(ih, il); + return bh; + } + + + /** + * Insert another list before Instruction handle ih contained in this list. + * Consumes argument list, i.e., it becomes empty. + * + * @param ih where to append the instruction list + * @param il Instruction list to insert + * @return instruction handle of the first inserted instruction + */ + public InstructionHandle insert( InstructionHandle ih, InstructionList il ) { + if (il == null) { + throw new ClassGenException("Inserting null InstructionList"); + } + if (il.isEmpty()) { + return ih; + } + InstructionHandle prev = ih.prev, ret = il.start; + ih.prev = il.end; + il.end.next = ih; + il.start.prev = prev; + if (prev != null) { + prev.next = il.start; + } else { + start = il.start; // Update start ... + } + length += il.length; // Update length + il.clear(); + return ret; + } + + + /** + * Insert another list. + * + * @param il list to insert before start of this list + * @return instruction handle of the first inserted instruction + */ + public InstructionHandle insert( InstructionList il ) { + if (isEmpty()) { + append(il); // Code is identical for this case + return start; + } else { + return insert(start, il); + } + } + + + /** + * Insert an instruction at start of this list. + * + * @param ih instruction to insert + */ + private void insert( InstructionHandle ih ) { + if (isEmpty()) { + start = end = ih; + ih.next = ih.prev = null; + } else { + start.prev = ih; + ih.next = start; + ih.prev = null; + start = ih; + } + length++; + } + + + /** + * Insert another list before Instruction i contained in this list. + * Consumes argument list, i.e., it becomes empty. + * + * @param i where to append the instruction list + * @param il Instruction list to insert + * @return instruction handle pointing to the first inserted instruction, + * i.e., il.getStart() + */ + public InstructionHandle insert( Instruction i, InstructionList il ) { + InstructionHandle ih; + if ((ih = findInstruction1(i)) == null) { + throw new ClassGenException("Instruction " + i + " is not contained in this list."); + } + return insert(ih, il); + } + + + /** + * Insert an instruction at start of this list. + * + * @param i instruction to insert + * @return instruction handle of the inserted instruction + */ + public InstructionHandle insert( Instruction i ) { + InstructionHandle ih = InstructionHandle.getInstructionHandle(i); + insert(ih); + return ih; + } + + + /** + * Insert a branch instruction at start of this list. + * + * @param i branch instruction to insert + * @return branch instruction handle of the appended instruction + */ + public BranchHandle insert( BranchInstruction i ) { + BranchHandle ih = BranchHandle.getBranchHandle(i); + insert(ih); + return ih; + } + + + /** + * Insert a single instruction j before another instruction i, which + * must be in this list of course! + * + * @param i Instruction in list + * @param j Instruction to insert before i in list + * @return instruction handle of the first inserted instruction + */ + public InstructionHandle insert( Instruction i, Instruction j ) { + return insert(i, new InstructionList(j)); + } + + + /** + * Insert a compound instruction before instruction i. + * + * @param i Instruction in list + * @param c The composite instruction (containing an InstructionList) + * @return instruction handle of the first inserted instruction + */ + public InstructionHandle insert( Instruction i, CompoundInstruction c ) { + return insert(i, c.getInstructionList()); + } + + + /** + * Insert a compound instruction. + * + * @param c The composite instruction (containing an InstructionList) + * @return instruction handle of the first inserted instruction + */ + public InstructionHandle insert( CompoundInstruction c ) { + return insert(c.getInstructionList()); + } + + + /** + * Insert an instruction before instruction (handle) ih contained in this list. + * + * @param ih where to insert to the instruction list + * @param i Instruction to insert + * @return instruction handle of the first inserted instruction + */ + public InstructionHandle insert( InstructionHandle ih, Instruction i ) { + return insert(ih, new InstructionList(i)); + } + + + /** + * Insert a compound instruction. + * + * @param ih where to insert the instruction list + * @param c The composite instruction (containing an InstructionList) + * @return instruction handle of the first inserted instruction + */ + public InstructionHandle insert( InstructionHandle ih, CompoundInstruction c ) { + return insert(ih, c.getInstructionList()); + } + + + /** + * Insert an instruction before instruction (handle) ih contained in this list. + * + * @param ih where to insert to the instruction list + * @param i Instruction to insert + * @return instruction handle of the first inserted instruction + */ + public BranchHandle insert( InstructionHandle ih, BranchInstruction i ) { + BranchHandle bh = BranchHandle.getBranchHandle(i); + InstructionList il = new InstructionList(); + il.append(bh); + insert(ih, il); + return bh; + } + + + /** + * Take all instructions (handles) from "start" to "end" and append them after the + * new location "target". Of course, "end" must be after "start" and target must + * not be located withing this range. If you want to move something to the start of + * the list use null as value for target.
      + * Any instruction targeters pointing to handles within the block, keep their targets. + * + * @param start of moved block + * @param end of moved block + * @param target of moved block + */ + public void move( InstructionHandle start, InstructionHandle end, InstructionHandle target ) { + // Step 1: Check constraints + if ((start == null) || (end == null)) { + throw new ClassGenException("Invalid null handle: From " + start + " to " + end); + } + if ((target == start) || (target == end)) { + throw new ClassGenException("Invalid range: From " + start + " to " + end + + " contains target " + target); + } + for (InstructionHandle ih = start; ih != end.next; ih = ih.next) { + if (ih == null) { + throw new ClassGenException("Invalid range: From " + start + " to " + end); + } else if (ih == target) { + throw new ClassGenException("Invalid range: From " + start + " to " + end + + " contains target " + target); + } + } + // Step 2: Temporarily remove the given instructions from the list + InstructionHandle prev = start.prev, next = end.next; + if (prev != null) { + prev.next = next; + } else { + this.start = next; + } + if (next != null) { + next.prev = prev; + } else { + this.end = prev; + } + start.prev = end.next = null; + // Step 3: append after target + if (target == null) { // append to start of list + if (this.start != null) { + this.start.prev = end; + } + end.next = this.start; + this.start = start; + } else { + next = target.next; + target.next = start; + start.prev = target; + end.next = next; + if (next != null) { + next.prev = end; + } else { + this.end = end; + } + } + } + + + /** + * Move a single instruction (handle) to a new location. + * + * @param ih moved instruction + * @param target new location of moved instruction + */ + public void move( InstructionHandle ih, InstructionHandle target ) { + move(ih, ih, target); + } + + + /** + * Remove from instruction `prev' to instruction `next' both contained + * in this list. Throws TargetLostException when one of the removed instruction handles + * is still being targeted. + * + * @param prev where to start deleting (predecessor, exclusive) + * @param next where to end deleting (successor, exclusive) + */ + private void remove( InstructionHandle prev, InstructionHandle next ) + throws TargetLostException { + InstructionHandle first, last; // First and last deleted instruction + if ((prev == null) && (next == null)) { // singleton list + first = last = start; + start = end = null; + } else { + if (prev == null) { // At start of list + first = start; + start = next; + } else { + first = prev.next; + prev.next = next; + } + if (next == null) { // At end of list + last = end; + end = prev; + } else { + last = next.prev; + next.prev = prev; + } + } + first.prev = null; // Completely separated from rest of list + last.next = null; + List target_vec = new ArrayList(); + for (InstructionHandle ih = first; ih != null; ih = ih.next) { + ih.getInstruction().dispose(); // e.g. BranchInstructions release their targets + } + StringBuffer buf = new StringBuffer("{ "); + for (InstructionHandle ih = first; ih != null; ih = next) { + next = ih.next; + length--; + if (ih.hasTargeters()) { // Still got targeters? + target_vec.add(ih); + buf.append(ih.toString(true) + " "); + ih.next = ih.prev = null; + } else { + ih.dispose(); + } + } + buf.append("}"); + if (!target_vec.isEmpty()) { + InstructionHandle[] targeted = new InstructionHandle[target_vec.size()]; + target_vec.toArray(targeted); + throw new TargetLostException(targeted, buf.toString()); + } + } + + + /** + * Remove instruction from this list. The corresponding Instruction + * handles must not be reused! + * + * @param ih instruction (handle) to remove + */ + public void delete( InstructionHandle ih ) throws TargetLostException { + remove(ih.prev, ih.next); + } + + + /** + * Remove instruction from this list. The corresponding Instruction + * handles must not be reused! + * + * @param i instruction to remove + */ + public void delete( Instruction i ) throws TargetLostException { + InstructionHandle ih; + if ((ih = findInstruction1(i)) == null) { + throw new ClassGenException("Instruction " + i + " is not contained in this list."); + } + delete(ih); + } + + + /** + * Remove instructions from instruction `from' to instruction `to' contained + * in this list. The user must ensure that `from' is an instruction before + * `to', or risk havoc. The corresponding Instruction handles must not be reused! + * + * @param from where to start deleting (inclusive) + * @param to where to end deleting (inclusive) + */ + public void delete( InstructionHandle from, InstructionHandle to ) throws TargetLostException { + remove(from.prev, to.next); + } + + + /** + * Remove instructions from instruction `from' to instruction `to' contained + * in this list. The user must ensure that `from' is an instruction before + * `to', or risk havoc. The corresponding Instruction handles must not be reused! + * + * @param from where to start deleting (inclusive) + * @param to where to end deleting (inclusive) + */ + public void delete( Instruction from, Instruction to ) throws TargetLostException { + InstructionHandle from_ih, to_ih; + if ((from_ih = findInstruction1(from)) == null) { + throw new ClassGenException("Instruction " + from + " is not contained in this list."); + } + if ((to_ih = findInstruction2(to)) == null) { + throw new ClassGenException("Instruction " + to + " is not contained in this list."); + } + delete(from_ih, to_ih); + } + + + /** + * Search for given Instruction reference, start at beginning of list. + * + * @param i instruction to search for + * @return instruction found on success, null otherwise + */ + private InstructionHandle findInstruction1( Instruction i ) { + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + if (ih.instruction == i) { + return ih; + } + } + return null; + } + + + /** + * Search for given Instruction reference, start at end of list + * + * @param i instruction to search for + * @return instruction found on success, null otherwise + */ + private InstructionHandle findInstruction2( Instruction i ) { + for (InstructionHandle ih = end; ih != null; ih = ih.prev) { + if (ih.instruction == i) { + return ih; + } + } + return null; + } + + + public boolean contains( InstructionHandle i ) { + if (i == null) { + return false; + } + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + if (ih == i) { + return true; + } + } + return false; + } + + + public boolean contains( Instruction i ) { + return findInstruction1(i) != null; + } + + + public void setPositions() { + setPositions(false); + } + + + /** + * Give all instructions their position number (offset in byte stream), i.e., + * make the list ready to be dumped. + * + * @param check Perform sanity checks, e.g. if all targeted instructions really belong + * to this list + */ + public void setPositions( boolean check ) { + int max_additional_bytes = 0, additional_bytes = 0; + int index = 0, count = 0; + int[] pos = new int[length]; + /* Pass 0: Sanity checks + */ + if (check) { + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + Instruction i = ih.instruction; + if (i instanceof BranchInstruction) { // target instruction within list? + Instruction inst = ((BranchInstruction) i).getTarget().instruction; + if (!contains(inst)) { + throw new ClassGenException("Branch target of " + + Constants.OPCODE_NAMES[i.opcode] + ":" + inst + + " not in instruction list"); + } + if (i instanceof Select) { + InstructionHandle[] targets = ((Select) i).getTargets(); + for (int j = 0; j < targets.length; j++) { + inst = targets[j].instruction; + if (!contains(inst)) { + throw new ClassGenException("Branch target of " + + Constants.OPCODE_NAMES[i.opcode] + ":" + inst + + " not in instruction list"); + } + } + } + if (!(ih instanceof BranchHandle)) { + throw new ClassGenException("Branch instruction " + + Constants.OPCODE_NAMES[i.opcode] + ":" + inst + + " not contained in BranchHandle."); + } + } + } + } + /* Pass 1: Set position numbers and sum up the maximum number of bytes an + * instruction may be shifted. + */ + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + Instruction i = ih.instruction; + ih.setPosition(index); + pos[count++] = index; + /* Get an estimate about how many additional bytes may be added, because + * BranchInstructions may have variable length depending on the target + * offset (short vs. int) or alignment issues (TABLESWITCH and + * LOOKUPSWITCH). + */ + switch (i.getOpcode()) { + case Constants.JSR: + case Constants.GOTO: + max_additional_bytes += 2; + break; + case Constants.TABLESWITCH: + case Constants.LOOKUPSWITCH: + max_additional_bytes += 3; + break; + } + index += i.getLength(); + } + /* Pass 2: Expand the variable-length (Branch)Instructions depending on + * the target offset (short or int) and ensure that branch targets are + * within this list. + */ + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + additional_bytes += ih.updatePosition(additional_bytes, max_additional_bytes); + } + /* Pass 3: Update position numbers (which may have changed due to the + * preceding expansions), like pass 1. + */ + index = count = 0; + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + Instruction i = ih.instruction; + ih.setPosition(index); + pos[count++] = index; + index += i.getLength(); + } + byte_positions = new int[count]; // Trim to proper size + System.arraycopy(pos, 0, byte_positions, 0, count); + } + + + /** + * When everything is finished, use this method to convert the instruction + * list into an array of bytes. + * + * @return the byte code ready to be dumped + */ + public byte[] getByteCode() { + // Update position indices of instructions + setPositions(); + ByteArrayOutputStream b = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(b); + try { + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + Instruction i = ih.instruction; + i.dump(out); // Traverse list + } + } catch (IOException e) { + System.err.println(e); + return null; + } + return b.toByteArray(); + } + + + /** + * @return an array of instructions without target information for branch instructions. + */ + public Instruction[] getInstructions() { + ByteSequence bytes = new ByteSequence(getByteCode()); + List instructions = new ArrayList(); + try { + while (bytes.available() > 0) { + instructions.add(Instruction.readInstruction(bytes)); + } + } catch (IOException e) { + throw new ClassGenException(e.toString()); + } + return (Instruction[]) instructions.toArray(new Instruction[instructions.size()]); + } + + + public String toString() { + return toString(true); + } + + + /** + * @param verbose toggle output format + * @return String containing all instructions in this list. + */ + public String toString( boolean verbose ) { + StringBuffer buf = new StringBuffer(); + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + buf.append(ih.toString(verbose)).append("\n"); + } + return buf.toString(); + } + + + /** + * @return Enumeration that lists all instructions (handles) + */ + public Iterator iterator() { + return new Iterator() { + + private InstructionHandle ih = start; + + + public Object next() { + InstructionHandle i = ih; + ih = ih.next; + return i; + } + + + public void remove() { + throw new UnsupportedOperationException(); + } + + + public boolean hasNext() { + return ih != null; + } + }; + } + + + /** + * @return array containing all instructions (handles) + */ + public InstructionHandle[] getInstructionHandles() { + InstructionHandle[] ihs = new InstructionHandle[length]; + InstructionHandle ih = start; + for (int i = 0; i < length; i++) { + ihs[i] = ih; + ih = ih.next; + } + return ihs; + } + + + /** + * Get positions (offsets) of all instructions in the list. This relies on that + * the list has been freshly created from an byte code array, or that setPositions() + * has been called. Otherwise this may be inaccurate. + * + * @return array containing all instruction's offset in byte code + */ + public int[] getInstructionPositions() { + return byte_positions; + } + + + /** + * @return complete, i.e., deep copy of this list + */ + public InstructionList copy() { + Map map = new HashMap(); + InstructionList il = new InstructionList(); + /* Pass 1: Make copies of all instructions, append them to the new list + * and associate old instruction references with the new ones, i.e., + * a 1:1 mapping. + */ + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + Instruction i = ih.instruction; + Instruction c = i.copy(); // Use clone for shallow copy + if (c instanceof BranchInstruction) { + map.put(ih, il.append((BranchInstruction) c)); + } else { + map.put(ih, il.append(c)); + } + } + /* Pass 2: Update branch targets. + */ + InstructionHandle ih = start; + InstructionHandle ch = il.start; + while (ih != null) { + Instruction i = ih.instruction; + Instruction c = ch.instruction; + if (i instanceof BranchInstruction) { + BranchInstruction bi = (BranchInstruction) i; + BranchInstruction bc = (BranchInstruction) c; + InstructionHandle itarget = bi.getTarget(); // old target + // New target is in hash map + bc.setTarget((InstructionHandle) map.get(itarget)); + if (bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH + InstructionHandle[] itargets = ((Select) bi).getTargets(); + InstructionHandle[] ctargets = ((Select) bc).getTargets(); + for (int j = 0; j < itargets.length; j++) { // Update all targets + ctargets[j] = (InstructionHandle) map.get(itargets[j]); + } + } + } + ih = ih.next; + ch = ch.next; + } + return il; + } + + + /** Replace all references to the old constant pool with references to the new + * constant pool + */ + public void replaceConstantPool( ConstantPoolGen old_cp, ConstantPoolGen new_cp ) { + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + Instruction i = ih.instruction; + if (i instanceof CPInstruction) { + CPInstruction ci = (CPInstruction) i; + Constant c = old_cp.getConstant(ci.getIndex()); + ci.setIndex(new_cp.addConstant(c, old_cp)); + } + } + } + + + private void clear() { + start = end = null; + length = 0; + } + + + /** + * Delete contents of list. Provides besser memory utilization, + * because the system then may reuse the instruction handles. This + * method is typically called right after + * MethodGen.getMethod(). + */ + public void dispose() { + // Traverse in reverse order, because ih.next is overwritten + for (InstructionHandle ih = end; ih != null; ih = ih.prev) { + /* Causes BranchInstructions to release target and targeters, because it + * calls dispose() on the contained instruction. + */ + ih.dispose(); + } + clear(); + } + + + /** + * @return start of list + */ + public InstructionHandle getStart() { + return start; + } + + + /** + * @return end of list + */ + public InstructionHandle getEnd() { + return end; + } + + + /** + * @return length of list (Number of instructions, not bytes) + */ + public int getLength() { + return length; + } + + + /** + * @return length of list (Number of instructions, not bytes) + */ + public int size() { + return length; + } + + + /** + * Redirect all references from old_target to new_target, i.e., update targets + * of branch instructions. + * + * @param old_target the old target instruction handle + * @param new_target the new target instruction handle + */ + public void redirectBranches( InstructionHandle old_target, InstructionHandle new_target ) { + for (InstructionHandle ih = start; ih != null; ih = ih.next) { + Instruction i = ih.getInstruction(); + if (i instanceof BranchInstruction) { + BranchInstruction b = (BranchInstruction) i; + InstructionHandle target = b.getTarget(); + if (target == old_target) { + b.setTarget(new_target); + } + if (b instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH + InstructionHandle[] targets = ((Select) b).getTargets(); + for (int j = 0; j < targets.length; j++) { + if (targets[j] == old_target) { + ((Select) b).setTarget(j, new_target); + } + } + } + } + } + } + + + /** + * Redirect all references of local variables from old_target to new_target. + * + * @param lg array of local variables + * @param old_target the old target instruction handle + * @param new_target the new target instruction handle + * @see MethodGen + */ + public void redirectLocalVariables( LocalVariableGen[] lg, InstructionHandle old_target, + InstructionHandle new_target ) { + for (int i = 0; i < lg.length; i++) { + InstructionHandle start = lg[i].getStart(); + InstructionHandle end = lg[i].getEnd(); + if (start == old_target) { + lg[i].setStart(new_target); + } + if (end == old_target) { + lg[i].setEnd(new_target); + } + } + } + + + /** + * Redirect all references of exception handlers from old_target to new_target. + * + * @param exceptions array of exception handlers + * @param old_target the old target instruction handle + * @param new_target the new target instruction handle + * @see MethodGen + */ + public void redirectExceptionHandlers( CodeExceptionGen[] exceptions, + InstructionHandle old_target, InstructionHandle new_target ) { + for (int i = 0; i < exceptions.length; i++) { + if (exceptions[i].getStartPC() == old_target) { + exceptions[i].setStartPC(new_target); + } + if (exceptions[i].getEndPC() == old_target) { + exceptions[i].setEndPC(new_target); + } + if (exceptions[i].getHandlerPC() == old_target) { + exceptions[i].setHandlerPC(new_target); + } + } + } + + private List observers; + + + /** Add observer for this object. + */ + public void addObserver( InstructionListObserver o ) { + if (observers == null) { + observers = new ArrayList(); + } + observers.add(o); + } + + + /** Remove observer for this object. + */ + public void removeObserver( InstructionListObserver o ) { + if (observers != null) { + observers.remove(o); + } + } + + + /** Call notify() method on all observers. This method is not called + * automatically whenever the state has changed, but has to be + * called by the user after he has finished editing the object. + */ + public void update() { + if (observers != null) { + for (Iterator e = observers.iterator(); e.hasNext();) { + ((InstructionListObserver) e.next()).notify(this); + } + } + } +} diff --git a/src/org/apache/bcel/generic/InstructionListObserver.java b/src/org/apache/bcel/generic/InstructionListObserver.java new file mode 100644 index 0000000..243b4fc --- /dev/null +++ b/src/org/apache/bcel/generic/InstructionListObserver.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Implement this interface if you're interested in changes to an InstructionList object + * and register yourself with addObserver(). + * + * @version $Id: InstructionListObserver.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface InstructionListObserver { + + public void notify( InstructionList list ); +} diff --git a/src/org/apache/bcel/generic/InstructionTargeter.java b/src/org/apache/bcel/generic/InstructionTargeter.java new file mode 100644 index 0000000..e096b3f --- /dev/null +++ b/src/org/apache/bcel/generic/InstructionTargeter.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denote that a class targets InstructionHandles within an InstructionList. Namely + * the following implementers: + * + * @see BranchHandle + * @see LocalVariableGen + * @see CodeExceptionGen + * @version $Id: InstructionTargeter.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface InstructionTargeter { + + public boolean containsTarget( InstructionHandle ih ); + + + public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ); +} diff --git a/src/org/apache/bcel/generic/InvokeInstruction.java b/src/org/apache/bcel/generic/InvokeInstruction.java new file mode 100644 index 0000000..2b12e5e --- /dev/null +++ b/src/org/apache/bcel/generic/InvokeInstruction.java @@ -0,0 +1,118 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.util.StringTokenizer; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.classfile.ConstantPool; + +/** + * Super class for the INVOKExxx family of instructions. + * + * @version $Id: InvokeInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class InvokeInstruction extends FieldOrMethod implements ExceptionThrower, + TypedInstruction, StackConsumer, StackProducer { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + InvokeInstruction() { + } + + + /** + * @param index to constant pool + */ + protected InvokeInstruction(short opcode, int index) { + super(opcode, index); + } + + + /** + * @return mnemonic for instruction with symbolic references resolved + */ + public String toString( ConstantPool cp ) { + Constant c = cp.getConstant(index); + StringTokenizer tok = new StringTokenizer(cp.constantToString(c)); + return Constants.OPCODE_NAMES[opcode] + " " + tok.nextToken().replace('.', '/') + + tok.nextToken(); + } + + + /** + * Also works for instructions whose stack effect depends on the + * constant pool entry they reference. + * @return Number of words consumed from stack by this instruction + */ + public int consumeStack( ConstantPoolGen cpg ) { + String signature = getSignature(cpg); + Type[] args = Type.getArgumentTypes(signature); + int sum; + if (opcode == Constants.INVOKESTATIC) { + sum = 0; + } else { + sum = 1; // this reference + } + int n = args.length; + for (int i = 0; i < n; i++) { + sum += args[i].getSize(); + } + return sum; + } + + + /** + * Also works for instructions whose stack effect depends on the + * constant pool entry they reference. + * @return Number of words produced onto stack by this instruction + */ + public int produceStack( ConstantPoolGen cpg ) { + return getReturnType(cpg).getSize(); + } + + + /** @return return type of referenced method. + */ + public Type getType( ConstantPoolGen cpg ) { + return getReturnType(cpg); + } + + + /** @return name of referenced method. + */ + public String getMethodName( ConstantPoolGen cpg ) { + return getName(cpg); + } + + + /** @return return type of referenced method. + */ + public Type getReturnType( ConstantPoolGen cpg ) { + return Type.getReturnType(getSignature(cpg)); + } + + + /** @return argument types of referenced method. + */ + public Type[] getArgumentTypes( ConstantPoolGen cpg ) { + return Type.getArgumentTypes(getSignature(cpg)); + } +} diff --git a/src/org/apache/bcel/generic/JSR.java b/src/org/apache/bcel/generic/JSR.java new file mode 100644 index 0000000..8e20e58 --- /dev/null +++ b/src/org/apache/bcel/generic/JSR.java @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * JSR - Jump to subroutine + * + * @version $Id: JSR.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class JSR extends JsrInstruction implements VariableLengthInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + JSR() { + } + + + public JSR(InstructionHandle target) { + super(org.apache.bcel.Constants.JSR, target); + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + index = getTargetOffset(); + if (opcode == org.apache.bcel.Constants.JSR) { + super.dump(out); + } else { // JSR_W + index = getTargetOffset(); + out.writeByte(opcode); + out.writeInt(index); + } + } + + + protected int updatePosition( int offset, int max_offset ) { + int i = getTargetOffset(); // Depending on old position value + position += offset; // Position may be shifted by preceding expansions + if (Math.abs(i) >= (32767 - max_offset)) { // to large for short (estimate) + opcode = org.apache.bcel.Constants.JSR_W; + length = 5; + return 2; // 5 - 3 + } + return 0; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitVariableLengthInstruction(this); + v.visitBranchInstruction(this); + v.visitJsrInstruction(this); + v.visitJSR(this); + } +} diff --git a/src/org/apache/bcel/generic/JSR_W.java b/src/org/apache/bcel/generic/JSR_W.java new file mode 100644 index 0000000..fbed4b6 --- /dev/null +++ b/src/org/apache/bcel/generic/JSR_W.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * JSR_W - Jump to subroutine + * + * @version $Id: JSR_W.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class JSR_W extends JsrInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + JSR_W() { + } + + + public JSR_W(InstructionHandle target) { + super(org.apache.bcel.Constants.JSR_W, target); + length = 5; + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + index = getTargetOffset(); + out.writeByte(opcode); + out.writeInt(index); + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + index = bytes.readInt(); + length = 5; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitBranchInstruction(this); + v.visitJsrInstruction(this); + v.visitJSR_W(this); + } +} diff --git a/src/org/apache/bcel/generic/JsrInstruction.java b/src/org/apache/bcel/generic/JsrInstruction.java new file mode 100644 index 0000000..80a5c9a --- /dev/null +++ b/src/org/apache/bcel/generic/JsrInstruction.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Super class for JSR - Jump to subroutine + * + * @version $Id: JsrInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class JsrInstruction extends BranchInstruction implements UnconditionalBranch, + TypedInstruction, StackProducer { + + JsrInstruction(short opcode, InstructionHandle target) { + super(opcode, target); + } + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + JsrInstruction() { + } + + + /** @return return address type + */ + public Type getType( ConstantPoolGen cp ) { + return new ReturnaddressType(physicalSuccessor()); + } + + + /** + * Returns an InstructionHandle to the physical successor + * of this JsrInstruction. For this method to work, + * this JsrInstruction object must not be shared between + * multiple InstructionHandle objects! + * Formally, there must not be InstructionHandle objects + * i, j where i != j and i.getInstruction() == this == + * j.getInstruction(). + * @return an InstructionHandle to the "next" instruction that + * will be executed when RETurned from a subroutine. + */ + public InstructionHandle physicalSuccessor() { + InstructionHandle ih = this.target; + // Rewind! + while (ih.getPrev() != null) { + ih = ih.getPrev(); + } + // Find the handle for "this" JsrInstruction object. + while (ih.getInstruction() != this) { + ih = ih.getNext(); + } + InstructionHandle toThis = ih; + while (ih != null) { + ih = ih.getNext(); + if ((ih != null) && (ih.getInstruction() == this)) { + throw new RuntimeException("physicalSuccessor() called on a shared JsrInstruction."); + } + } + // Return the physical successor + return toThis.getNext(); + } +} diff --git a/src/org/apache/bcel/generic/L2D.java b/src/org/apache/bcel/generic/L2D.java new file mode 100644 index 0000000..345aac8 --- /dev/null +++ b/src/org/apache/bcel/generic/L2D.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * L2D - Convert long to double + *
      Stack: ..., value.word1, value.word2 -> ..., result.word1, result.word2
      + * + * @version $Id: L2D.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class L2D extends ConversionInstruction { + + public L2D() { + super(org.apache.bcel.Constants.L2D); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitL2D(this); + } +} diff --git a/src/org/apache/bcel/generic/L2F.java b/src/org/apache/bcel/generic/L2F.java new file mode 100644 index 0000000..17e63ff --- /dev/null +++ b/src/org/apache/bcel/generic/L2F.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * L2F - Convert long to float + *
      Stack: ..., value.word1, value.word2 -> ..., result
      + * + * @version $Id: L2F.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class L2F extends ConversionInstruction { + + public L2F() { + super(org.apache.bcel.Constants.L2F); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitL2F(this); + } +} diff --git a/src/org/apache/bcel/generic/L2I.java b/src/org/apache/bcel/generic/L2I.java new file mode 100644 index 0000000..be495b4 --- /dev/null +++ b/src/org/apache/bcel/generic/L2I.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * L2I - Convert long to int + *
      Stack: ..., value.word1, value.word2 -> ..., result
      + * + * @version $Id: L2I.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class L2I extends ConversionInstruction { + + public L2I() { + super(org.apache.bcel.Constants.L2I); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitConversionInstruction(this); + v.visitL2I(this); + } +} diff --git a/src/org/apache/bcel/generic/LADD.java b/src/org/apache/bcel/generic/LADD.java new file mode 100644 index 0000000..d2e38e0 --- /dev/null +++ b/src/org/apache/bcel/generic/LADD.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LADD - Add longs + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result.word1, result.word2 + * + * @version $Id: LADD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LADD extends ArithmeticInstruction { + + public LADD() { + super(org.apache.bcel.Constants.LADD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLADD(this); + } +} diff --git a/src/org/apache/bcel/generic/LALOAD.java b/src/org/apache/bcel/generic/LALOAD.java new file mode 100644 index 0000000..d0704ed --- /dev/null +++ b/src/org/apache/bcel/generic/LALOAD.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LALOAD - Load long from array + *
      Stack: ..., arrayref, index -> ..., value1, value2
      + * + * @version $Id: LALOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LALOAD extends ArrayInstruction implements StackProducer { + + /** Load long from array + */ + public LALOAD() { + super(org.apache.bcel.Constants.LALOAD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitLALOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/LAND.java b/src/org/apache/bcel/generic/LAND.java new file mode 100644 index 0000000..1659e4d --- /dev/null +++ b/src/org/apache/bcel/generic/LAND.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LAND - Bitwise AND longs + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result.word1, result.word2 + * + * @version $Id: LAND.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LAND extends ArithmeticInstruction { + + public LAND() { + super(org.apache.bcel.Constants.LAND); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLAND(this); + } +} diff --git a/src/org/apache/bcel/generic/LASTORE.java b/src/org/apache/bcel/generic/LASTORE.java new file mode 100644 index 0000000..e620e9f --- /dev/null +++ b/src/org/apache/bcel/generic/LASTORE.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LASTORE - Store into long array + *
      Stack: ..., arrayref, index, value.word1, value.word2 -> ...
      + * + * @version $Id: LASTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LASTORE extends ArrayInstruction implements StackConsumer { + + /** Store long into array + */ + public LASTORE() { + super(org.apache.bcel.Constants.LASTORE); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitLASTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/LCMP.java b/src/org/apache/bcel/generic/LCMP.java new file mode 100644 index 0000000..2371924 --- /dev/null +++ b/src/org/apache/bcel/generic/LCMP.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LCMP - Compare longs: + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result <= -1, 0, 1> + * + * @version $Id: LCMP.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LCMP extends Instruction implements TypedInstruction, StackProducer, StackConsumer { + + public LCMP() { + super(org.apache.bcel.Constants.LCMP, (short) 1); + } + + + /** @return Type.LONG + */ + public Type getType( ConstantPoolGen cp ) { + return Type.LONG; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitLCMP(this); + } +} diff --git a/src/org/apache/bcel/generic/LCONST.java b/src/org/apache/bcel/generic/LCONST.java new file mode 100644 index 0000000..92fd60f --- /dev/null +++ b/src/org/apache/bcel/generic/LCONST.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LCONST - Push 0 or 1, other values cause an exception + * + *
      Stack: ... -> ..., 
      + * + * @version $Id: LCONST.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LCONST extends Instruction implements ConstantPushInstruction, TypedInstruction { + + private long value; + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + LCONST() { + } + + + public LCONST(long l) { + super(org.apache.bcel.Constants.LCONST_0, (short) 1); + if (l == 0) { + opcode = org.apache.bcel.Constants.LCONST_0; + } else if (l == 1) { + opcode = org.apache.bcel.Constants.LCONST_1; + } else { + throw new ClassGenException("LCONST can be used only for 0 and 1: " + l); + } + value = l; + } + + + public Number getValue() { + return new Long(value); + } + + + /** @return Type.LONG + */ + public Type getType( ConstantPoolGen cp ) { + return Type.LONG; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitPushInstruction(this); + v.visitStackProducer(this); + v.visitTypedInstruction(this); + v.visitConstantPushInstruction(this); + v.visitLCONST(this); + } +} diff --git a/src/org/apache/bcel/generic/LDC.java b/src/org/apache/bcel/generic/LDC.java new file mode 100644 index 0000000..3f93694 --- /dev/null +++ b/src/org/apache/bcel/generic/LDC.java @@ -0,0 +1,148 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * LDC - Push item from constant pool. + * + *
      Stack: ... -> ..., item
      + * + * @version $Id: LDC.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LDC extends CPInstruction implements PushInstruction, ExceptionThrower, + TypedInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + LDC() { + } + + + public LDC(int index) { + super(org.apache.bcel.Constants.LDC_W, index); + setSize(); + } + + + // Adjust to proper size + protected final void setSize() { + if (index <= org.apache.bcel.Constants.MAX_BYTE) { // Fits in one byte? + opcode = org.apache.bcel.Constants.LDC; + length = 2; + } else { + opcode = org.apache.bcel.Constants.LDC_W; + length = 3; + } + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + out.writeByte(opcode); + if (length == 2) { + out.writeByte(index); + } else { + out.writeShort(index); + } + } + + + /** + * Set the index to constant pool and adjust size. + */ + public final void setIndex( int index ) { + super.setIndex(index); + setSize(); + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + length = 2; + index = bytes.readUnsignedByte(); + } + + + public Object getValue( ConstantPoolGen cpg ) { + org.apache.bcel.classfile.Constant c = cpg.getConstantPool().getConstant(index); + switch (c.getTag()) { + case org.apache.bcel.Constants.CONSTANT_String: + int i = ((org.apache.bcel.classfile.ConstantString) c).getStringIndex(); + c = cpg.getConstantPool().getConstant(i); + return ((org.apache.bcel.classfile.ConstantUtf8) c).getBytes(); + case org.apache.bcel.Constants.CONSTANT_Float: + return new Float(((org.apache.bcel.classfile.ConstantFloat) c).getBytes()); + case org.apache.bcel.Constants.CONSTANT_Integer: + return new Integer(((org.apache.bcel.classfile.ConstantInteger) c).getBytes()); + case org.apache.bcel.Constants.CONSTANT_Class: + return c; + default: // Never reached + throw new RuntimeException("Unknown or invalid constant type at " + index); + } + } + + + public Type getType( ConstantPoolGen cpg ) { + switch (cpg.getConstantPool().getConstant(index).getTag()) { + case org.apache.bcel.Constants.CONSTANT_String: + return Type.STRING; + case org.apache.bcel.Constants.CONSTANT_Float: + return Type.FLOAT; + case org.apache.bcel.Constants.CONSTANT_Integer: + return Type.INT; + case org.apache.bcel.Constants.CONSTANT_Class: + return Type.CLASS; + default: // Never reached + throw new RuntimeException("Unknown or invalid constant type at " + index); + } + } + + + public Class[] getExceptions() { + return org.apache.bcel.ExceptionConstants.EXCS_STRING_RESOLUTION; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitPushInstruction(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitCPInstruction(this); + v.visitLDC(this); + } +} diff --git a/src/org/apache/bcel/generic/LDC2_W.java b/src/org/apache/bcel/generic/LDC2_W.java new file mode 100644 index 0000000..dacfc19 --- /dev/null +++ b/src/org/apache/bcel/generic/LDC2_W.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LDC2_W - Push long or double from constant pool + * + *
      Stack: ... -> ..., item.word1, item.word2
      + * + * @version $Id: LDC2_W.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LDC2_W extends CPInstruction implements PushInstruction, TypedInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + LDC2_W() { + } + + + public LDC2_W(int index) { + super(org.apache.bcel.Constants.LDC2_W, index); + } + + + public Type getType( ConstantPoolGen cpg ) { + switch (cpg.getConstantPool().getConstant(index).getTag()) { + case org.apache.bcel.Constants.CONSTANT_Long: + return Type.LONG; + case org.apache.bcel.Constants.CONSTANT_Double: + return Type.DOUBLE; + default: // Never reached + throw new RuntimeException("Unknown constant type " + opcode); + } + } + + + public Number getValue( ConstantPoolGen cpg ) { + org.apache.bcel.classfile.Constant c = cpg.getConstantPool().getConstant(index); + switch (c.getTag()) { + case org.apache.bcel.Constants.CONSTANT_Long: + return new Long(((org.apache.bcel.classfile.ConstantLong) c).getBytes()); + case org.apache.bcel.Constants.CONSTANT_Double: + return new Double(((org.apache.bcel.classfile.ConstantDouble) c).getBytes()); + default: // Never reached + throw new RuntimeException("Unknown or invalid constant type at " + index); + } + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitPushInstruction(this); + v.visitTypedInstruction(this); + v.visitCPInstruction(this); + v.visitLDC2_W(this); + } +} diff --git a/src/org/apache/bcel/generic/LDC_W.java b/src/org/apache/bcel/generic/LDC_W.java new file mode 100644 index 0000000..4621ccd --- /dev/null +++ b/src/org/apache/bcel/generic/LDC_W.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * LDC_W - Push item from constant pool (wide index) + * + *
      Stack: ... -> ..., item.word1, item.word2
      + * + * @version $Id: LDC_W.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LDC_W extends LDC { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + LDC_W() { + } + + + public LDC_W(int index) { + super(index); + } + + + /** + * Read needed data (i.e., index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + setIndex(bytes.readUnsignedShort()); + // Override just in case it has been changed + opcode = org.apache.bcel.Constants.LDC_W; + length = 3; + } +} diff --git a/src/org/apache/bcel/generic/LDIV.java b/src/org/apache/bcel/generic/LDIV.java new file mode 100644 index 0000000..f734ada --- /dev/null +++ b/src/org/apache/bcel/generic/LDIV.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LDIV - Divide longs + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result.word1, result.word2 + * + * @version $Id: LDIV.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LDIV extends ArithmeticInstruction implements ExceptionThrower { + + public LDIV() { + super(org.apache.bcel.Constants.LDIV); + } + + + public Class[] getExceptions() { + return new Class[] { + org.apache.bcel.ExceptionConstants.ARITHMETIC_EXCEPTION + }; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLDIV(this); + } +} diff --git a/src/org/apache/bcel/generic/LLOAD.java b/src/org/apache/bcel/generic/LLOAD.java new file mode 100644 index 0000000..bdf5fe4 --- /dev/null +++ b/src/org/apache/bcel/generic/LLOAD.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LLOAD - Load long from local variable + *
      Stack ... -> ..., result.word1, result.word2
      + * + * @version $Id: LLOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LLOAD extends LoadInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + LLOAD() { + super(org.apache.bcel.Constants.LLOAD, org.apache.bcel.Constants.LLOAD_0); + } + + + public LLOAD(int n) { + super(org.apache.bcel.Constants.LLOAD, org.apache.bcel.Constants.LLOAD_0, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + super.accept(v); + v.visitLLOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/LMUL.java b/src/org/apache/bcel/generic/LMUL.java new file mode 100644 index 0000000..ff41bdb --- /dev/null +++ b/src/org/apache/bcel/generic/LMUL.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LMUL - Multiply longs + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result.word1, result.word2 + * + * @version $Id: LMUL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LMUL extends ArithmeticInstruction { + + public LMUL() { + super(org.apache.bcel.Constants.LMUL); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLMUL(this); + } +} diff --git a/src/org/apache/bcel/generic/LNEG.java b/src/org/apache/bcel/generic/LNEG.java new file mode 100644 index 0000000..d30d2cc --- /dev/null +++ b/src/org/apache/bcel/generic/LNEG.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LNEG - Negate long + *
      Stack: ..., value.word1, value.word2 -> ..., result.word1, result.word2
      + * + * @version $Id: LNEG.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LNEG extends ArithmeticInstruction { + + public LNEG() { + super(org.apache.bcel.Constants.LNEG); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLNEG(this); + } +} diff --git a/src/org/apache/bcel/generic/LOOKUPSWITCH.java b/src/org/apache/bcel/generic/LOOKUPSWITCH.java new file mode 100644 index 0000000..e85fff1 --- /dev/null +++ b/src/org/apache/bcel/generic/LOOKUPSWITCH.java @@ -0,0 +1,95 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * LOOKUPSWITCH - Switch with unordered set of values + * + * @version $Id: LOOKUPSWITCH.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see SWITCH + */ +public class LOOKUPSWITCH extends Select { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + LOOKUPSWITCH() { + } + + + public LOOKUPSWITCH(int[] match, InstructionHandle[] targets, InstructionHandle defaultTarget) { + super(org.apache.bcel.Constants.LOOKUPSWITCH, match, targets, defaultTarget); + length = (short) (9 + match_length * 8); /* alignment remainder assumed + * 0 here, until dump time. */ + fixed_length = length; + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + super.dump(out); + out.writeInt(match_length); // npairs + for (int i = 0; i < match_length; i++) { + out.writeInt(match[i]); // match-offset pairs + out.writeInt(indices[i] = getTargetOffset(targets[i])); + } + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + super.initFromFile(bytes, wide); // reads padding + match_length = bytes.readInt(); + fixed_length = (short) (9 + match_length * 8); + length = (short) (fixed_length + padding); + match = new int[match_length]; + indices = new int[match_length]; + targets = new InstructionHandle[match_length]; + for (int i = 0; i < match_length; i++) { + match[i] = bytes.readInt(); + indices[i] = bytes.readInt(); + } + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitVariableLengthInstruction(this); + v.visitStackProducer(this); + v.visitBranchInstruction(this); + v.visitSelect(this); + v.visitLOOKUPSWITCH(this); + } +} diff --git a/src/org/apache/bcel/generic/LOR.java b/src/org/apache/bcel/generic/LOR.java new file mode 100644 index 0000000..2d716e9 --- /dev/null +++ b/src/org/apache/bcel/generic/LOR.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LOR - Bitwise OR long + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: LOR.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LOR extends ArithmeticInstruction { + + public LOR() { + super(org.apache.bcel.Constants.LOR); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLOR(this); + } +} diff --git a/src/org/apache/bcel/generic/LREM.java b/src/org/apache/bcel/generic/LREM.java new file mode 100644 index 0000000..12bdd40 --- /dev/null +++ b/src/org/apache/bcel/generic/LREM.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LREM - Remainder of long + *
      Stack: ..., value1, value2 -> result
      + * + * @version $Id: LREM.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LREM extends ArithmeticInstruction implements ExceptionThrower { + + public LREM() { + super(org.apache.bcel.Constants.LREM); + } + + + public Class[] getExceptions() { + return new Class[] { + org.apache.bcel.ExceptionConstants.ARITHMETIC_EXCEPTION + }; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLREM(this); + } +} diff --git a/src/org/apache/bcel/generic/LRETURN.java b/src/org/apache/bcel/generic/LRETURN.java new file mode 100644 index 0000000..161b39e --- /dev/null +++ b/src/org/apache/bcel/generic/LRETURN.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LRETURN - Return long from method + *
      Stack: ..., value.word1, value.word2 -> <empty>
      + * + * @version $Id: LRETURN.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LRETURN extends ReturnInstruction { + + public LRETURN() { + super(org.apache.bcel.Constants.LRETURN); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitReturnInstruction(this); + v.visitLRETURN(this); + } +} diff --git a/src/org/apache/bcel/generic/LSHL.java b/src/org/apache/bcel/generic/LSHL.java new file mode 100644 index 0000000..980504b --- /dev/null +++ b/src/org/apache/bcel/generic/LSHL.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LSHL - Arithmetic shift left long + *
      Stack: ..., value1.word1, value1.word2, value2 -> ..., result.word1, result.word2
      + * + * @version $Id: LSHL.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LSHL extends ArithmeticInstruction { + + public LSHL() { + super(org.apache.bcel.Constants.LSHL); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLSHL(this); + } +} diff --git a/src/org/apache/bcel/generic/LSHR.java b/src/org/apache/bcel/generic/LSHR.java new file mode 100644 index 0000000..68c2cf5 --- /dev/null +++ b/src/org/apache/bcel/generic/LSHR.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LSHR - Arithmetic shift right long + *
      Stack: ..., value1.word1, value1.word2, value2 -> ..., result.word1, result.word2
      + * + * @version $Id: LSHR.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LSHR extends ArithmeticInstruction { + + public LSHR() { + super(org.apache.bcel.Constants.LSHR); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLSHR(this); + } +} diff --git a/src/org/apache/bcel/generic/LSTORE.java b/src/org/apache/bcel/generic/LSTORE.java new file mode 100644 index 0000000..988ab6f --- /dev/null +++ b/src/org/apache/bcel/generic/LSTORE.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LSTORE - Store long into local variable + *
      Stack: ..., value.word1, value.word2 -> ... 
      + * + * @version $Id: LSTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LSTORE extends StoreInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + LSTORE() { + super(org.apache.bcel.Constants.LSTORE, org.apache.bcel.Constants.LSTORE_0); + } + + + public LSTORE(int n) { + super(org.apache.bcel.Constants.LSTORE, org.apache.bcel.Constants.LSTORE_0, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + super.accept(v); + v.visitLSTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/LSUB.java b/src/org/apache/bcel/generic/LSUB.java new file mode 100644 index 0000000..9155902 --- /dev/null +++ b/src/org/apache/bcel/generic/LSUB.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LSUB - Substract longs + *
      Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
      + * ..., result.word1, result.word2 + * + * @version $Id: LSUB.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LSUB extends ArithmeticInstruction { + + public LSUB() { + super(org.apache.bcel.Constants.LSUB); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLSUB(this); + } +} diff --git a/src/org/apache/bcel/generic/LUSHR.java b/src/org/apache/bcel/generic/LUSHR.java new file mode 100644 index 0000000..ee65857 --- /dev/null +++ b/src/org/apache/bcel/generic/LUSHR.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LUSHR - Logical shift right long + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: LUSHR.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LUSHR extends ArithmeticInstruction { + + public LUSHR() { + super(org.apache.bcel.Constants.LUSHR); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLUSHR(this); + } +} diff --git a/src/org/apache/bcel/generic/LXOR.java b/src/org/apache/bcel/generic/LXOR.java new file mode 100644 index 0000000..33090a8 --- /dev/null +++ b/src/org/apache/bcel/generic/LXOR.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * LXOR - Bitwise XOR long + *
      Stack: ..., value1, value2 -> ..., result
      + * + * @version $Id: LXOR.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class LXOR extends ArithmeticInstruction { + + public LXOR() { + super(org.apache.bcel.Constants.LXOR); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitTypedInstruction(this); + v.visitStackProducer(this); + v.visitStackConsumer(this); + v.visitArithmeticInstruction(this); + v.visitLXOR(this); + } +} diff --git a/src/org/apache/bcel/generic/LineNumberGen.java b/src/org/apache/bcel/generic/LineNumberGen.java new file mode 100644 index 0000000..d34045f --- /dev/null +++ b/src/org/apache/bcel/generic/LineNumberGen.java @@ -0,0 +1,108 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.classfile.LineNumber; + +/** + * This class represents a line number within a method, i.e., give an instruction + * a line number corresponding to the source code line. + * + * @version $Id: LineNumberGen.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see LineNumber + * @see MethodGen + */ +public class LineNumberGen implements InstructionTargeter, Cloneable, java.io.Serializable { + + private InstructionHandle ih; + private int src_line; + + + /** + * Create a line number. + * + * @param ih instruction handle to reference + */ + public LineNumberGen(InstructionHandle ih, int src_line) { + setInstruction(ih); + setSourceLine(src_line); + } + + + /** + * @return true, if ih is target of this line number + */ + public boolean containsTarget( InstructionHandle ih ) { + return this.ih == ih; + } + + + /** + * @param old_ih old target + * @param new_ih new target + */ + public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ) { + if (old_ih != ih) { + throw new ClassGenException("Not targeting " + old_ih + ", but " + ih + "}"); + } else { + setInstruction(new_ih); + } + } + + + /** + * Get LineNumber attribute . + * + * This relies on that the instruction list has already been dumped to byte code or + * or that the `setPositions' methods has been called for the instruction list. + */ + public LineNumber getLineNumber() { + return new LineNumber(ih.getPosition(), src_line); + } + + + public void setInstruction( InstructionHandle ih ) { + BranchInstruction.notifyTarget(this.ih, ih, this); + this.ih = ih; + } + + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + System.err.println(e); + return null; + } + } + + + public InstructionHandle getInstruction() { + return ih; + } + + + public void setSourceLine( int src_line ) { + this.src_line = src_line; + } + + + public int getSourceLine() { + return src_line; + } +} diff --git a/src/org/apache/bcel/generic/LoadClass.java b/src/org/apache/bcel/generic/LoadClass.java new file mode 100644 index 0000000..4633acf --- /dev/null +++ b/src/org/apache/bcel/generic/LoadClass.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denotes that an instruction may start the process of loading and resolving + * the referenced class in the Virtual Machine. + * + * @version $Id: LoadClass.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface LoadClass { + + /** + * Returns the ObjectType of the referenced class or interface + * that may be loaded and resolved. + * @return object type that may be loaded or null if a primitive is + * referenced + */ + public ObjectType getLoadClassType( ConstantPoolGen cpg ); + + + /** + * Returns the type associated with this instruction. + * LoadClass instances are always typed, but this type + * does not always refer to the type of the class or interface + * that it possibly forces to load. For example, GETFIELD would + * return the type of the field and not the type of the class + * where the field is defined. + * If no class is forced to be loaded, null is returned. + * An example for this is an ANEWARRAY instruction that creates + * an int[][]. + * @see #getLoadClassType(ConstantPoolGen) + */ + public Type getType( ConstantPoolGen cpg ); +} diff --git a/src/org/apache/bcel/generic/LoadInstruction.java b/src/org/apache/bcel/generic/LoadInstruction.java new file mode 100644 index 0000000..9f46d10 --- /dev/null +++ b/src/org/apache/bcel/generic/LoadInstruction.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denotes an unparameterized instruction to load a value from a local + * variable, e.g. ILOAD. + * + * @version $Id: LoadInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class LoadInstruction extends LocalVariableInstruction implements PushInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + * tag and length are defined in readInstruction and initFromFile, respectively. + */ + LoadInstruction(short canon_tag, short c_tag) { + super(canon_tag, c_tag); + } + + + /** + * @param opcode Instruction opcode + * @param c_tag Instruction number for compact version, ALOAD_0, e.g. + * @param n local variable index (unsigned short) + */ + protected LoadInstruction(short opcode, short c_tag, int n) { + super(opcode, c_tag, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitPushInstruction(this); + v.visitTypedInstruction(this); + v.visitLocalVariableInstruction(this); + v.visitLoadInstruction(this); + } +} diff --git a/src/org/apache/bcel/generic/LocalVariableGen.java b/src/org/apache/bcel/generic/LocalVariableGen.java new file mode 100644 index 0000000..b5eb8fc --- /dev/null +++ b/src/org/apache/bcel/generic/LocalVariableGen.java @@ -0,0 +1,208 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.LocalVariable; + +/** + * This class represents a local variable within a method. It contains its + * scope, name and type. The generated LocalVariable object can be obtained + * with getLocalVariable which needs the instruction list and the constant + * pool as parameters. + * + * @version $Id: LocalVariableGen.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see LocalVariable + * @see MethodGen + */ +public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable, + java.io.Serializable { + + private int index; + private String name; + private Type type; + private InstructionHandle start, end; + + + /** + * Generate a local variable that with index `index'. Note that double and long + * variables need two indexs. Index indices have to be provided by the user. + * + * @param index index of local variable + * @param name its name + * @param type its type + * @param start from where the instruction is valid (null means from the start) + * @param end until where the instruction is valid (null means to the end) + */ + public LocalVariableGen(int index, String name, Type type, InstructionHandle start, + InstructionHandle end) { + if ((index < 0) || (index > Constants.MAX_SHORT)) { + throw new ClassGenException("Invalid index index: " + index); + } + this.name = name; + this.type = type; + this.index = index; + setStart(start); + setEnd(end); + } + + + /** + * Get LocalVariable object. + * + * This relies on that the instruction list has already been dumped to byte code or + * or that the `setPositions' methods has been called for the instruction list. + * + * Note that for local variables whose scope end at the last + * instruction of the method's code, the JVM specification is ambiguous: + * both a start_pc+length ending at the last instruction and + * start_pc+length ending at first index beyond the end of the code are + * valid. + * + * @param cp constant pool + */ + public LocalVariable getLocalVariable( ConstantPoolGen cp ) { + int start_pc = start.getPosition(); + int length = end.getPosition() - start_pc; + if (length > 0) { + length += end.getInstruction().getLength(); + } + int name_index = cp.addUtf8(name); + int signature_index = cp.addUtf8(type.getSignature()); + return new LocalVariable(start_pc, length, name_index, signature_index, index, cp + .getConstantPool()); + } + + + public void setIndex( int index ) { + this.index = index; + } + + + public int getIndex() { + return index; + } + + + public void setName( String name ) { + this.name = name; + } + + + public String getName() { + return name; + } + + + public void setType( Type type ) { + this.type = type; + } + + + public Type getType() { + return type; + } + + + public InstructionHandle getStart() { + return start; + } + + + public InstructionHandle getEnd() { + return end; + } + + + public void setStart( InstructionHandle start ) { + BranchInstruction.notifyTarget(this.start, start, this); + this.start = start; + } + + + public void setEnd( InstructionHandle end ) { + BranchInstruction.notifyTarget(this.end, end, this); + this.end = end; + } + + + /** + * @param old_ih old target, either start or end + * @param new_ih new target + */ + public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ) { + boolean targeted = false; + if (start == old_ih) { + targeted = true; + setStart(new_ih); + } + if (end == old_ih) { + targeted = true; + setEnd(new_ih); + } + if (!targeted) { + throw new ClassGenException("Not targeting " + old_ih + ", but {" + start + ", " + end + + "}"); + } + } + + + /** + * @return true, if ih is target of this variable + */ + public boolean containsTarget( InstructionHandle ih ) { + return (start == ih) || (end == ih); + } + + + /** @return a hash code value for the object. + */ + public int hashCode() { + //If the user changes the name or type, problems with the targeter hashmap will occur + int hc = index ^ name.hashCode() ^ type.hashCode(); + return hc; + } + + + /** + * We consider to local variables to be equal, if the use the same index and + * are valid in the same range. + */ + public boolean equals( Object o ) { + if (!(o instanceof LocalVariableGen)) { + return false; + } + LocalVariableGen l = (LocalVariableGen) o; + return (l.index == index) && (l.start == start) && (l.end == end); + } + + + public String toString() { + return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")"; + } + + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + System.err.println(e); + return null; + } + } +} diff --git a/src/org/apache/bcel/generic/LocalVariableInstruction.java b/src/org/apache/bcel/generic/LocalVariableInstruction.java new file mode 100644 index 0000000..3f8d953 --- /dev/null +++ b/src/org/apache/bcel/generic/LocalVariableInstruction.java @@ -0,0 +1,202 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.Constants; +import org.apache.bcel.util.ByteSequence; + +/** + * Abstract super class for instructions dealing with local variables. + * + * @version $Id: LocalVariableInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction, + IndexedInstruction { + + protected int n = -1; // index of referenced variable + private short c_tag = -1; // compact version, such as ILOAD_0 + private short canon_tag = -1; // canonical tag such as ILOAD + + + private final boolean wide() { + return n > Constants.MAX_BYTE; + } + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + * tag and length are defined in readInstruction and initFromFile, respectively. + */ + LocalVariableInstruction(short canon_tag, short c_tag) { + super(); + this.canon_tag = canon_tag; + this.c_tag = c_tag; + } + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Also used by IINC()! + */ + LocalVariableInstruction() { + } + + + /** + * @param opcode Instruction opcode + * @param c_tag Instruction number for compact version, ALOAD_0, e.g. + * @param n local variable index (unsigned short) + */ + protected LocalVariableInstruction(short opcode, short c_tag, int n) { + super(opcode, (short) 2); + this.c_tag = c_tag; + canon_tag = opcode; + setIndex(n); + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + if (wide()) { + out.writeByte(Constants.WIDE); + } + out.writeByte(opcode); + if (length > 1) { // Otherwise ILOAD_n, instruction, e.g. + if (wide()) { + out.writeShort(n); + } else { + out.writeByte(n); + } + } + } + + + /** + * Long output format: + * + * <name of opcode> "["<opcode number>"]" + * "("<length of instruction>")" "<"< local variable index>">" + * + * @param verbose long/short format switch + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + if (((opcode >= Constants.ILOAD_0) && (opcode <= Constants.ALOAD_3)) + || ((opcode >= Constants.ISTORE_0) && (opcode <= Constants.ASTORE_3))) { + return super.toString(verbose); + } else { + return super.toString(verbose) + " " + n; + } + } + + + /** + * Read needed data (e.g. index) from file. + * PRE: (ILOAD <= tag <= ALOAD_3) || (ISTORE <= tag <= ASTORE_3) + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + if (wide) { + n = bytes.readUnsignedShort(); + length = 4; + } else if (((opcode >= Constants.ILOAD) && (opcode <= Constants.ALOAD)) + || ((opcode >= Constants.ISTORE) && (opcode <= Constants.ASTORE))) { + n = bytes.readUnsignedByte(); + length = 2; + } else if (opcode <= Constants.ALOAD_3) { // compact load instruction such as ILOAD_2 + n = (opcode - Constants.ILOAD_0) % 4; + length = 1; + } else { // Assert ISTORE_0 <= tag <= ASTORE_3 + n = (opcode - Constants.ISTORE_0) % 4; + length = 1; + } + } + + + /** + * @return local variable index referred by this instruction. + */ + public final int getIndex() { + return n; + } + + + /** + * Set the local variable index + */ + public void setIndex( int n ) { + if ((n < 0) || (n > Constants.MAX_SHORT)) { + throw new ClassGenException("Illegal value: " + n); + } + this.n = n; + if (n >= 0 && n <= 3) { // Use more compact instruction xLOAD_n + opcode = (short) (c_tag + n); + length = 1; + } else { + opcode = canon_tag; + if (wide()) { + length = 4; + } else { + length = 2; + } + } + } + + + /** @return canonical tag for instruction, e.g., ALOAD for ALOAD_0 + */ + public short getCanonicalTag() { + return canon_tag; + } + + + /** + * Returns the type associated with the instruction - + * in case of ALOAD or ASTORE Type.OBJECT is returned. + * This is just a bit incorrect, because ALOAD and ASTORE + * may work on every ReferenceType (including Type.NULL) and + * ASTORE may even work on a ReturnaddressType . + * @return type associated with the instruction + */ + public Type getType( ConstantPoolGen cp ) { + switch (canon_tag) { + case Constants.ILOAD: + case Constants.ISTORE: + return Type.INT; + case Constants.LLOAD: + case Constants.LSTORE: + return Type.LONG; + case Constants.DLOAD: + case Constants.DSTORE: + return Type.DOUBLE; + case Constants.FLOAD: + case Constants.FSTORE: + return Type.FLOAT; + case Constants.ALOAD: + case Constants.ASTORE: + return Type.OBJECT; + default: + throw new ClassGenException("Oops: unknown case in switch" + canon_tag); + } + } +} diff --git a/src/org/apache/bcel/generic/MONITORENTER.java b/src/org/apache/bcel/generic/MONITORENTER.java new file mode 100644 index 0000000..1f115f7 --- /dev/null +++ b/src/org/apache/bcel/generic/MONITORENTER.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * MONITORENTER - Enter monitor for object + *
      Stack: ..., objectref -> ...
      + * + * @version $Id: MONITORENTER.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class MONITORENTER extends Instruction implements ExceptionThrower, StackConsumer { + + public MONITORENTER() { + super(org.apache.bcel.Constants.MONITORENTER, (short) 1); + } + + + public Class[] getExceptions() { + return new Class[] { + org.apache.bcel.ExceptionConstants.NULL_POINTER_EXCEPTION + }; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitStackConsumer(this); + v.visitMONITORENTER(this); + } +} diff --git a/src/org/apache/bcel/generic/MONITOREXIT.java b/src/org/apache/bcel/generic/MONITOREXIT.java new file mode 100644 index 0000000..29ecbd5 --- /dev/null +++ b/src/org/apache/bcel/generic/MONITOREXIT.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * MONITOREXIT - Exit monitor for object + *
      Stack: ..., objectref -> ...
      + * + * @version $Id: MONITOREXIT.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class MONITOREXIT extends Instruction implements ExceptionThrower, StackConsumer { + + public MONITOREXIT() { + super(org.apache.bcel.Constants.MONITOREXIT, (short) 1); + } + + + public Class[] getExceptions() { + return new Class[] { + org.apache.bcel.ExceptionConstants.NULL_POINTER_EXCEPTION + }; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitStackConsumer(this); + v.visitMONITOREXIT(this); + } +} diff --git a/src/org/apache/bcel/generic/MULTIANEWARRAY.java b/src/org/apache/bcel/generic/MULTIANEWARRAY.java new file mode 100644 index 0000000..0709f15 --- /dev/null +++ b/src/org/apache/bcel/generic/MULTIANEWARRAY.java @@ -0,0 +1,146 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.ExceptionConstants; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.util.ByteSequence; + +/** + * MULTIANEWARRAY - Create new mutidimensional array of references + *
      Stack: ..., count1, [count2, ...] -> ..., arrayref
      + * + * @version $Id: MULTIANEWARRAY.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class MULTIANEWARRAY extends CPInstruction implements LoadClass, AllocationInstruction, + ExceptionThrower { + + private short dimensions; + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + MULTIANEWARRAY() { + } + + + public MULTIANEWARRAY(int index, short dimensions) { + super(org.apache.bcel.Constants.MULTIANEWARRAY, index); + if (dimensions < 1) { + throw new ClassGenException("Invalid dimensions value: " + dimensions); + } + this.dimensions = dimensions; + length = 4; + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + out.writeByte(opcode); + out.writeShort(index); + out.writeByte(dimensions); + } + + + /** + * Read needed data (i.e., no. dimension) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + super.initFromFile(bytes, wide); + dimensions = bytes.readByte(); + length = 4; + } + + + /** + * @return number of dimensions to be created + */ + public final short getDimensions() { + return dimensions; + } + + + /** + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + return super.toString(verbose) + " " + index + " " + dimensions; + } + + + /** + * @return mnemonic for instruction with symbolic references resolved + */ + public String toString( ConstantPool cp ) { + return super.toString(cp) + " " + dimensions; + } + + + /** + * Also works for instructions whose stack effect depends on the + * constant pool entry they reference. + * @return Number of words consumed from stack by this instruction + */ + public int consumeStack( ConstantPoolGen cpg ) { + return dimensions; + } + + + public Class[] getExceptions() { + Class[] cs = new Class[2 + ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length); + cs[ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length + 1] = ExceptionConstants.NEGATIVE_ARRAY_SIZE_EXCEPTION; + cs[ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length] = ExceptionConstants.ILLEGAL_ACCESS_ERROR; + return cs; + } + + + public ObjectType getLoadClassType( ConstantPoolGen cpg ) { + Type t = getType(cpg); + if (t instanceof ArrayType) { + t = ((ArrayType) t).getBasicType(); + } + return (t instanceof ObjectType) ? (ObjectType) t : null; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitLoadClass(this); + v.visitAllocationInstruction(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitCPInstruction(this); + v.visitMULTIANEWARRAY(this); + } +} diff --git a/src/org/apache/bcel/generic/MethodGen.java b/src/org/apache/bcel/generic/MethodGen.java new file mode 100644 index 0000000..ff816d5 --- /dev/null +++ b/src/org/apache/bcel/generic/MethodGen.java @@ -0,0 +1,1086 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.Attribute; +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.CodeException; +import org.apache.bcel.classfile.ExceptionTable; +import org.apache.bcel.classfile.LineNumber; +import org.apache.bcel.classfile.LineNumberTable; +import org.apache.bcel.classfile.LocalVariable; +import org.apache.bcel.classfile.LocalVariableTable; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.Utility; +import org.apache.bcel.util.BCELComparator; + +/** + * Template class for building up a method. This is done by defining exception + * handlers, adding thrown exceptions, local variables and attributes, whereas + * the `LocalVariableTable' and `LineNumberTable' attributes will be set + * automatically for the code. Use stripAttributes() if you don't like this. + * + * While generating code it may be necessary to insert NOP operations. You can + * use the `removeNOPs' method to get rid off them. + * The resulting method object can be obtained via the `getMethod()' method. + * + * @version $Id: MethodGen.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @author Patrick C. Beard [setMaxStack()] + * @see InstructionList + * @see Method + */ +public class MethodGen extends FieldGenOrMethodGen { + + private String class_name; + private Type[] arg_types; + private String[] arg_names; + private int max_locals; + private int max_stack; + private InstructionList il; + private boolean strip_attributes; + private List variable_vec = new ArrayList(); + private List line_number_vec = new ArrayList(); + private List exception_vec = new ArrayList(); + private List throws_vec = new ArrayList(); + private List code_attrs_vec = new ArrayList(); + private static BCELComparator _cmp = new BCELComparator() { + + public boolean equals( Object o1, Object o2 ) { + MethodGen THIS = (MethodGen) o1; + MethodGen THAT = (MethodGen) o2; + return THIS.getName().equals(THAT.getName()) + && THIS.getSignature().equals(THAT.getSignature()); + } + + + public int hashCode( Object o ) { + MethodGen THIS = (MethodGen) o; + return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + } + }; + + + /** + * Declare method. If the method is non-static the constructor + * automatically declares a local variable `$this' in slot 0. The + * actual code is contained in the `il' parameter, which may further + * manipulated by the user. But he must take care not to remove any + * instruction (handles) that are still referenced from this object. + * + * For example one may not add a local variable and later remove the + * instructions it refers to without causing havoc. It is safe + * however if you remove that local variable, too. + * + * @param access_flags access qualifiers + * @param return_type method type + * @param arg_types argument types + * @param arg_names argument names (if this is null, default names will be provided + * for them) + * @param method_name name of method + * @param class_name class name containing this method (may be null, if you don't care) + * @param il instruction list associated with this method, may be null only for + * abstract or native methods + * @param cp constant pool + */ + public MethodGen(int access_flags, Type return_type, Type[] arg_types, String[] arg_names, + String method_name, String class_name, InstructionList il, ConstantPoolGen cp) { + setAccessFlags(access_flags); + setType(return_type); + setArgumentTypes(arg_types); + setArgumentNames(arg_names); + setName(method_name); + setClassName(class_name); + setInstructionList(il); + setConstantPool(cp); + boolean abstract_ = isAbstract() || isNative(); + InstructionHandle start = null; + InstructionHandle end = null; + if (!abstract_) { + start = il.getStart(); + end = il.getEnd(); + /* Add local variables, namely the implicit `this' and the arguments + */ + if (!isStatic() && (class_name != null)) { // Instance method -> `this' is local var 0 + addLocalVariable("this", new ObjectType(class_name), start, end); + } + } + if (arg_types != null) { + int size = arg_types.length; + for (int i = 0; i < size; i++) { + if (Type.VOID == arg_types[i]) { + throw new ClassGenException("'void' is an illegal argument type for a method"); + } + } + if (arg_names != null) { // Names for variables provided? + if (size != arg_names.length) { + throw new ClassGenException("Mismatch in argument array lengths: " + size + + " vs. " + arg_names.length); + } + } else { // Give them dummy names + arg_names = new String[size]; + for (int i = 0; i < size; i++) { + arg_names[i] = "arg" + i; + } + setArgumentNames(arg_names); + } + if (!abstract_) { + for (int i = 0; i < size; i++) { + addLocalVariable(arg_names[i], arg_types[i], start, end); + } + } + } + } + + + /** + * Instantiate from existing method. + * + * @param m method + * @param class_name class name containing this method + * @param cp constant pool + */ + public MethodGen(Method m, String class_name, ConstantPoolGen cp) { + this(m.getAccessFlags(), Type.getReturnType(m.getSignature()), Type.getArgumentTypes(m + .getSignature()), null /* may be overridden anyway */ + , m.getName(), class_name, + ((m.getAccessFlags() & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0) + ? new InstructionList(m.getCode().getCode()) + : null, cp); + Attribute[] attributes = m.getAttributes(); + for (int i = 0; i < attributes.length; i++) { + Attribute a = attributes[i]; + if (a instanceof Code) { + Code c = (Code) a; + setMaxStack(c.getMaxStack()); + setMaxLocals(c.getMaxLocals()); + CodeException[] ces = c.getExceptionTable(); + if (ces != null) { + for (int j = 0; j < ces.length; j++) { + CodeException ce = ces[j]; + int type = ce.getCatchType(); + ObjectType c_type = null; + if (type > 0) { + String cen = m.getConstantPool().getConstantString(type, + Constants.CONSTANT_Class); + c_type = new ObjectType(cen); + } + int end_pc = ce.getEndPC(); + int length = m.getCode().getCode().length; + InstructionHandle end; + if (length == end_pc) { // May happen, because end_pc is exclusive + end = il.getEnd(); + } else { + end = il.findHandle(end_pc); + end = end.getPrev(); // Make it inclusive + } + addExceptionHandler(il.findHandle(ce.getStartPC()), end, il.findHandle(ce + .getHandlerPC()), c_type); + } + } + Attribute[] c_attributes = c.getAttributes(); + for (int j = 0; j < c_attributes.length; j++) { + a = c_attributes[j]; + if (a instanceof LineNumberTable) { + LineNumber[] ln = ((LineNumberTable) a).getLineNumberTable(); + for (int k = 0; k < ln.length; k++) { + LineNumber l = ln[k]; + InstructionHandle ih = il.findHandle(l.getStartPC()); + if (ih != null) { + addLineNumber(ih, l.getLineNumber()); + } + } + } else if (a instanceof LocalVariableTable) { + LocalVariable[] lv = ((LocalVariableTable) a).getLocalVariableTable(); + removeLocalVariables(); + for (int k = 0; k < lv.length; k++) { + LocalVariable l = lv[k]; + InstructionHandle start = il.findHandle(l.getStartPC()); + InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength()); + // Repair malformed handles + if (null == start) { + start = il.getStart(); + } + if (null == end) { + end = il.getEnd(); + } + addLocalVariable(l.getName(), Type.getType(l.getSignature()), l + .getIndex(), start, end); + } + } else { + addCodeAttribute(a); + } + } + } else if (a instanceof ExceptionTable) { + String[] names = ((ExceptionTable) a).getExceptionNames(); + for (int j = 0; j < names.length; j++) { + addException(names[j]); + } + } else { + addAttribute(a); + } + } + } + + + /** + * Adds a local variable to this method. + * + * @param name variable name + * @param type variable type + * @param slot the index of the local variable, if type is long or double, the next available + * index is slot+2 + * @param start from where the variable is valid + * @param end until where the variable is valid + * @return new local variable object + * @see LocalVariable + */ + public LocalVariableGen addLocalVariable( String name, Type type, int slot, + InstructionHandle start, InstructionHandle end ) { + byte t = type.getType(); + if (t != Constants.T_ADDRESS) { + int add = type.getSize(); + if (slot + add > max_locals) { + max_locals = slot + add; + } + LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end); + int i; + if ((i = variable_vec.indexOf(l)) >= 0) { + variable_vec.set(i, l); + } else { + variable_vec.add(l); + } + return l; + } else { + throw new IllegalArgumentException("Can not use " + type + + " as type for local variable"); + } + } + + + /** + * Adds a local variable to this method and assigns an index automatically. + * + * @param name variable name + * @param type variable type + * @param start from where the variable is valid, if this is null, + * it is valid from the start + * @param end until where the variable is valid, if this is null, + * it is valid to the end + * @return new local variable object + * @see LocalVariable + */ + public LocalVariableGen addLocalVariable( String name, Type type, InstructionHandle start, + InstructionHandle end ) { + return addLocalVariable(name, type, max_locals, start, end); + } + + + /** + * Remove a local variable, its slot will not be reused, if you do not use addLocalVariable + * with an explicit index argument. + */ + public void removeLocalVariable( LocalVariableGen l ) { + variable_vec.remove(l); + } + + + /** + * Remove all local variables. + */ + public void removeLocalVariables() { + variable_vec.clear(); + } + + + /** + * Sort local variables by index + */ + private static final void sort( LocalVariableGen[] vars, int l, int r ) { + int i = l, j = r; + int m = vars[(l + r) / 2].getIndex(); + LocalVariableGen h; + do { + while (vars[i].getIndex() < m) { + i++; + } + while (m < vars[j].getIndex()) { + j--; + } + if (i <= j) { + h = vars[i]; + vars[i] = vars[j]; + vars[j] = h; // Swap elements + i++; + j--; + } + } while (i <= j); + if (l < j) { + sort(vars, l, j); + } + if (i < r) { + sort(vars, i, r); + } + } + + + /* + * If the range of the variable has not been set yet, it will be set to be valid from + * the start to the end of the instruction list. + * + * @return array of declared local variables sorted by index + */ + public LocalVariableGen[] getLocalVariables() { + int size = variable_vec.size(); + LocalVariableGen[] lg = new LocalVariableGen[size]; + variable_vec.toArray(lg); + for (int i = 0; i < size; i++) { + if (lg[i].getStart() == null) { + lg[i].setStart(il.getStart()); + } + if (lg[i].getEnd() == null) { + lg[i].setEnd(il.getEnd()); + } + } + if (size > 1) { + sort(lg, 0, size - 1); + } + return lg; + } + + + /** + * @return `LocalVariableTable' attribute of all the local variables of this method. + */ + public LocalVariableTable getLocalVariableTable( ConstantPoolGen cp ) { + LocalVariableGen[] lg = getLocalVariables(); + int size = lg.length; + LocalVariable[] lv = new LocalVariable[size]; + for (int i = 0; i < size; i++) { + lv[i] = lg[i].getLocalVariable(cp); + } + return new LocalVariableTable(cp.addUtf8("LocalVariableTable"), 2 + lv.length * 10, lv, cp + .getConstantPool()); + } + + + /** + * Give an instruction a line number corresponding to the source code line. + * + * @param ih instruction to tag + * @return new line number object + * @see LineNumber + */ + public LineNumberGen addLineNumber( InstructionHandle ih, int src_line ) { + LineNumberGen l = new LineNumberGen(ih, src_line); + line_number_vec.add(l); + return l; + } + + + /** + * Remove a line number. + */ + public void removeLineNumber( LineNumberGen l ) { + line_number_vec.remove(l); + } + + + /** + * Remove all line numbers. + */ + public void removeLineNumbers() { + line_number_vec.clear(); + } + + + /* + * @return array of line numbers + */ + public LineNumberGen[] getLineNumbers() { + LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()]; + line_number_vec.toArray(lg); + return lg; + } + + + /** + * @return `LineNumberTable' attribute of all the local variables of this method. + */ + public LineNumberTable getLineNumberTable( ConstantPoolGen cp ) { + int size = line_number_vec.size(); + LineNumber[] ln = new LineNumber[size]; + try { + for (int i = 0; i < size; i++) { + ln[i] = ((LineNumberGen) line_number_vec.get(i)).getLineNumber(); + } + } catch (ArrayIndexOutOfBoundsException e) { + } // Never occurs + return new LineNumberTable(cp.addUtf8("LineNumberTable"), 2 + ln.length * 4, ln, cp + .getConstantPool()); + } + + + /** + * Add an exception handler, i.e., specify region where a handler is active and an + * instruction where the actual handling is done. + * + * @param start_pc Start of region (inclusive) + * @param end_pc End of region (inclusive) + * @param handler_pc Where handling is done + * @param catch_type class type of handled exception or null if any + * exception is handled + * @return new exception handler object + */ + public CodeExceptionGen addExceptionHandler( InstructionHandle start_pc, + InstructionHandle end_pc, InstructionHandle handler_pc, ObjectType catch_type ) { + if ((start_pc == null) || (end_pc == null) || (handler_pc == null)) { + throw new ClassGenException("Exception handler target is null instruction"); + } + CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc, handler_pc, catch_type); + exception_vec.add(c); + return c; + } + + + /** + * Remove an exception handler. + */ + public void removeExceptionHandler( CodeExceptionGen c ) { + exception_vec.remove(c); + } + + + /** + * Remove all line numbers. + */ + public void removeExceptionHandlers() { + exception_vec.clear(); + } + + + /* + * @return array of declared exception handlers + */ + public CodeExceptionGen[] getExceptionHandlers() { + CodeExceptionGen[] cg = new CodeExceptionGen[exception_vec.size()]; + exception_vec.toArray(cg); + return cg; + } + + + /** + * @return code exceptions for `Code' attribute + */ + private CodeException[] getCodeExceptions() { + int size = exception_vec.size(); + CodeException[] c_exc = new CodeException[size]; + try { + for (int i = 0; i < size; i++) { + CodeExceptionGen c = (CodeExceptionGen) exception_vec.get(i); + c_exc[i] = c.getCodeException(cp); + } + } catch (ArrayIndexOutOfBoundsException e) { + } + return c_exc; + } + + + /** + * Add an exception possibly thrown by this method. + * + * @param class_name (fully qualified) name of exception + */ + public void addException( String class_name ) { + throws_vec.add(class_name); + } + + + /** + * Remove an exception. + */ + public void removeException( String c ) { + throws_vec.remove(c); + } + + + /** + * Remove all exceptions. + */ + public void removeExceptions() { + throws_vec.clear(); + } + + + /* + * @return array of thrown exceptions + */ + public String[] getExceptions() { + String[] e = new String[throws_vec.size()]; + throws_vec.toArray(e); + return e; + } + + + /** + * @return `Exceptions' attribute of all the exceptions thrown by this method. + */ + private ExceptionTable getExceptionTable( ConstantPoolGen cp ) { + int size = throws_vec.size(); + int[] ex = new int[size]; + try { + for (int i = 0; i < size; i++) { + ex[i] = cp.addClass((String) throws_vec.get(i)); + } + } catch (ArrayIndexOutOfBoundsException e) { + } + return new ExceptionTable(cp.addUtf8("Exceptions"), 2 + 2 * size, ex, cp.getConstantPool()); + } + + + /** + * Add an attribute to the code. Currently, the JVM knows about the + * LineNumberTable, LocalVariableTable and StackMap attributes, + * where the former two will be generated automatically and the + * latter is used for the MIDP only. Other attributes will be + * ignored by the JVM but do no harm. + * + * @param a attribute to be added + */ + public void addCodeAttribute( Attribute a ) { + code_attrs_vec.add(a); + } + + + /** + * Remove a code attribute. + */ + public void removeCodeAttribute( Attribute a ) { + code_attrs_vec.remove(a); + } + + + /** + * Remove all code attributes. + */ + public void removeCodeAttributes() { + code_attrs_vec.clear(); + } + + + /** + * @return all attributes of this method. + */ + public Attribute[] getCodeAttributes() { + Attribute[] attributes = new Attribute[code_attrs_vec.size()]; + code_attrs_vec.toArray(attributes); + return attributes; + } + + + /** + * Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively, + * before calling this method (the same applies for max locals). + * + * @return method object + */ + public Method getMethod() { + String signature = getSignature(); + int name_index = cp.addUtf8(name); + int signature_index = cp.addUtf8(signature); + /* Also updates positions of instructions, i.e., their indices + */ + byte[] byte_code = null; + if (il != null) { + byte_code = il.getByteCode(); + } + LineNumberTable lnt = null; + LocalVariableTable lvt = null; + /* Create LocalVariableTable and LineNumberTable attributes (for debuggers, e.g.) + */ + if ((variable_vec.size() > 0) && !strip_attributes) { + addCodeAttribute(lvt = getLocalVariableTable(cp)); + } + if ((line_number_vec.size() > 0) && !strip_attributes) { + addCodeAttribute(lnt = getLineNumberTable(cp)); + } + Attribute[] code_attrs = getCodeAttributes(); + /* Each attribute causes 6 additional header bytes + */ + int attrs_len = 0; + for (int i = 0; i < code_attrs.length; i++) { + attrs_len += (code_attrs[i].getLength() + 6); + } + CodeException[] c_exc = getCodeExceptions(); + int exc_len = c_exc.length * 8; // Every entry takes 8 bytes + Code code = null; + if ((il != null) && !isAbstract() && !isNative()) { + // Remove any stale code attribute + Attribute[] attributes = getAttributes(); + for (int i = 0; i < attributes.length; i++) { + Attribute a = attributes[i]; + if (a instanceof Code) { + removeAttribute(a); + } + } + code = new Code(cp.addUtf8("Code"), 8 + byte_code.length + // prologue byte code + 2 + exc_len + // exceptions + 2 + attrs_len, // attributes + max_stack, max_locals, byte_code, c_exc, code_attrs, cp.getConstantPool()); + addAttribute(code); + } + ExceptionTable et = null; + if (throws_vec.size() > 0) { + addAttribute(et = getExceptionTable(cp)); + // Add `Exceptions' if there are "throws" clauses + } + Method m = new Method(access_flags, name_index, signature_index, getAttributes(), cp + .getConstantPool()); + // Undo effects of adding attributes + if (lvt != null) { + removeCodeAttribute(lvt); + } + if (lnt != null) { + removeCodeAttribute(lnt); + } + if (code != null) { + removeAttribute(code); + } + if (et != null) { + removeAttribute(et); + } + return m; + } + + + /** + * Remove all NOPs from the instruction list (if possible) and update every + * object refering to them, i.e., branch instructions, local variables and + * exception handlers. + */ + public void removeNOPs() { + if (il != null) { + InstructionHandle next; + /* Check branch instructions. + */ + for (InstructionHandle ih = il.getStart(); ih != null; ih = next) { + next = ih.next; + if ((next != null) && (ih.getInstruction() instanceof NOP)) { + try { + il.delete(ih); + } catch (TargetLostException e) { + InstructionHandle[] targets = e.getTargets(); + for (int i = 0; i < targets.length; i++) { + InstructionTargeter[] targeters = targets[i].getTargeters(); + for (int j = 0; j < targeters.length; j++) { + targeters[j].updateTarget(targets[i], next); + } + } + } + } + } + } + } + + + /** + * Set maximum number of local variables. + */ + public void setMaxLocals( int m ) { + max_locals = m; + } + + + public int getMaxLocals() { + return max_locals; + } + + + /** + * Set maximum stack size for this method. + */ + public void setMaxStack( int m ) { + max_stack = m; + } + + + public int getMaxStack() { + return max_stack; + } + + + /** @return class that contains this method + */ + public String getClassName() { + return class_name; + } + + + public void setClassName( String class_name ) { + this.class_name = class_name; + } + + + public void setReturnType( Type return_type ) { + setType(return_type); + } + + + public Type getReturnType() { + return getType(); + } + + + public void setArgumentTypes( Type[] arg_types ) { + this.arg_types = arg_types; + } + + + public Type[] getArgumentTypes() { + return (Type[]) arg_types.clone(); + } + + + public void setArgumentType( int i, Type type ) { + arg_types[i] = type; + } + + + public Type getArgumentType( int i ) { + return arg_types[i]; + } + + + public void setArgumentNames( String[] arg_names ) { + this.arg_names = arg_names; + } + + + public String[] getArgumentNames() { + return (String[]) arg_names.clone(); + } + + + public void setArgumentName( int i, String name ) { + arg_names[i] = name; + } + + + public String getArgumentName( int i ) { + return arg_names[i]; + } + + + public InstructionList getInstructionList() { + return il; + } + + + public void setInstructionList( InstructionList il ) { + this.il = il; + } + + + public String getSignature() { + return Type.getMethodSignature(type, arg_types); + } + + + /** + * Computes max. stack size by performing control flow analysis. + */ + public void setMaxStack() { + if (il != null) { + max_stack = getMaxStack(cp, il, getExceptionHandlers()); + } else { + max_stack = 0; + } + } + + + /** + * Compute maximum number of local variables. + */ + public void setMaxLocals() { + if (il != null) { + int max = isStatic() ? 0 : 1; + if (arg_types != null) { + for (int i = 0; i < arg_types.length; i++) { + max += arg_types[i].getSize(); + } + } + for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) { + Instruction ins = ih.getInstruction(); + if ((ins instanceof LocalVariableInstruction) || (ins instanceof RET) + || (ins instanceof IINC)) { + int index = ((IndexedInstruction) ins).getIndex() + + ((TypedInstruction) ins).getType(cp).getSize(); + if (index > max) { + max = index; + } + } + } + max_locals = max; + } else { + max_locals = 0; + } + } + + + /** Do not/Do produce attributes code attributesLineNumberTable and + * LocalVariableTable, like javac -O + */ + public void stripAttributes( boolean flag ) { + strip_attributes = flag; + } + + static final class BranchTarget { + + InstructionHandle target; + int stackDepth; + + + BranchTarget(InstructionHandle target, int stackDepth) { + this.target = target; + this.stackDepth = stackDepth; + } + } + + static final class BranchStack { + + Stack branchTargets = new Stack(); + Hashtable visitedTargets = new Hashtable(); + + + public void push( InstructionHandle target, int stackDepth ) { + if (visited(target)) { + return; + } + branchTargets.push(visit(target, stackDepth)); + } + + + public BranchTarget pop() { + if (!branchTargets.empty()) { + BranchTarget bt = (BranchTarget) branchTargets.pop(); + return bt; + } + return null; + } + + + private final BranchTarget visit( InstructionHandle target, int stackDepth ) { + BranchTarget bt = new BranchTarget(target, stackDepth); + visitedTargets.put(target, bt); + return bt; + } + + + private final boolean visited( InstructionHandle target ) { + return (visitedTargets.get(target) != null); + } + } + + + /** + * Computes stack usage of an instruction list by performing control flow analysis. + * + * @return maximum stack depth used by method + */ + public static int getMaxStack( ConstantPoolGen cp, InstructionList il, CodeExceptionGen[] et ) { + BranchStack branchTargets = new BranchStack(); + /* Initially, populate the branch stack with the exception + * handlers, because these aren't (necessarily) branched to + * explicitly. in each case, the stack will have depth 1, + * containing the exception object. + */ + for (int i = 0; i < et.length; i++) { + InstructionHandle handler_pc = et[i].getHandlerPC(); + if (handler_pc != null) { + branchTargets.push(handler_pc, 1); + } + } + int stackDepth = 0, maxStackDepth = 0; + InstructionHandle ih = il.getStart(); + while (ih != null) { + Instruction instruction = ih.getInstruction(); + short opcode = instruction.getOpcode(); + int delta = instruction.produceStack(cp) - instruction.consumeStack(cp); + stackDepth += delta; + if (stackDepth > maxStackDepth) { + maxStackDepth = stackDepth; + } + // choose the next instruction based on whether current is a branch. + if (instruction instanceof BranchInstruction) { + BranchInstruction branch = (BranchInstruction) instruction; + if (instruction instanceof Select) { + // explore all of the select's targets. the default target is handled below. + Select select = (Select) branch; + InstructionHandle[] targets = select.getTargets(); + for (int i = 0; i < targets.length; i++) { + branchTargets.push(targets[i], stackDepth); + } + // nothing to fall through to. + ih = null; + } else if (!(branch instanceof IfInstruction)) { + // if an instruction that comes back to following PC, + // push next instruction, with stack depth reduced by 1. + if (opcode == Constants.JSR || opcode == Constants.JSR_W) { + branchTargets.push(ih.getNext(), stackDepth - 1); + } + ih = null; + } + // for all branches, the target of the branch is pushed on the branch stack. + // conditional branches have a fall through case, selects don't, and + // jsr/jsr_w return to the next instruction. + branchTargets.push(branch.getTarget(), stackDepth); + } else { + // check for instructions that terminate the method. + if (opcode == Constants.ATHROW || opcode == Constants.RET + || (opcode >= Constants.IRETURN && opcode <= Constants.RETURN)) { + ih = null; + } + } + // normal case, go to the next instruction. + if (ih != null) { + ih = ih.getNext(); + } + // if we have no more instructions, see if there are any deferred branches to explore. + if (ih == null) { + BranchTarget bt = branchTargets.pop(); + if (bt != null) { + ih = bt.target; + stackDepth = bt.stackDepth; + } + } + } + return maxStackDepth; + } + + private List observers; + + + /** Add observer for this object. + */ + public void addObserver( MethodObserver o ) { + if (observers == null) { + observers = new ArrayList(); + } + observers.add(o); + } + + + /** Remove observer for this object. + */ + public void removeObserver( MethodObserver o ) { + if (observers != null) { + observers.remove(o); + } + } + + + /** Call notify() method on all observers. This method is not called + * automatically whenever the state has changed, but has to be + * called by the user after he has finished editing the object. + */ + public void update() { + if (observers != null) { + for (Iterator e = observers.iterator(); e.hasNext();) { + ((MethodObserver) e.next()).notify(this); + } + } + } + + + /** + * Return string representation close to declaration format, + * `public static void main(String[]) throws IOException', e.g. + * + * @return String representation of the method. + */ + public final String toString() { + String access = Utility.accessToString(access_flags); + String signature = Type.getMethodSignature(type, arg_types); + signature = Utility.methodSignatureToString(signature, name, access, true, + getLocalVariableTable(cp)); + StringBuffer buf = new StringBuffer(signature); + if (throws_vec.size() > 0) { + for (Iterator e = throws_vec.iterator(); e.hasNext();) { + buf.append("\n\t\tthrows ").append(e.next()); + } + } + return buf.toString(); + } + + + /** @return deep copy of this method + */ + public MethodGen copy( String class_name, ConstantPoolGen cp ) { + Method m = ((MethodGen) clone()).getMethod(); + MethodGen mg = new MethodGen(m, class_name, this.cp); + if (this.cp != cp) { + mg.setConstantPool(cp); + mg.getInstructionList().replaceConstantPool(this.cp, cp); + } + return mg; + } + + + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return _cmp; + } + + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator( BCELComparator comparator ) { + _cmp = comparator; + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default two MethodGen objects are said to be equal when + * their names and signatures are equal. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals( Object obj ) { + return _cmp.equals(this, obj); + } + + + /** + * Return value as defined by given BCELComparator strategy. + * By default return the hashcode of the method's name XOR signature. + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return _cmp.hashCode(this); + } +} diff --git a/src/org/apache/bcel/generic/MethodObserver.java b/src/org/apache/bcel/generic/MethodObserver.java new file mode 100644 index 0000000..dae3bf4 --- /dev/null +++ b/src/org/apache/bcel/generic/MethodObserver.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Implement this interface if you're interested in changes to a MethodGen object + * and register yourself with addObserver(). + * + * @version $Id: MethodObserver.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface MethodObserver { + + public void notify( MethodGen method ); +} diff --git a/src/org/apache/bcel/generic/NEW.java b/src/org/apache/bcel/generic/NEW.java new file mode 100644 index 0000000..705a6cd --- /dev/null +++ b/src/org/apache/bcel/generic/NEW.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.ExceptionConstants; + +/** + * NEW - Create new object + *
      Stack: ... -> ..., objectref
      + * + * @version $Id: NEW.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class NEW extends CPInstruction implements LoadClass, AllocationInstruction, + ExceptionThrower, StackProducer { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + NEW() { + } + + + public NEW(int index) { + super(org.apache.bcel.Constants.NEW, index); + } + + + public Class[] getExceptions() { + Class[] cs = new Class[2 + ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length); + cs[ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length + 1] = ExceptionConstants.INSTANTIATION_ERROR; + cs[ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length] = ExceptionConstants.ILLEGAL_ACCESS_ERROR; + return cs; + } + + + public ObjectType getLoadClassType( ConstantPoolGen cpg ) { + return (ObjectType) getType(cpg); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitLoadClass(this); + v.visitAllocationInstruction(this); + v.visitExceptionThrower(this); + v.visitStackProducer(this); + v.visitTypedInstruction(this); + v.visitCPInstruction(this); + v.visitNEW(this); + } +} diff --git a/src/org/apache/bcel/generic/NEWARRAY.java b/src/org/apache/bcel/generic/NEWARRAY.java new file mode 100644 index 0000000..276a4ee --- /dev/null +++ b/src/org/apache/bcel/generic/NEWARRAY.java @@ -0,0 +1,120 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * NEWARRAY - Create new array of basic type (int, short, ...) + *
      Stack: ..., count -> ..., arrayref
      + * type must be one of T_INT, T_SHORT, ... + * + * @version $Id: NEWARRAY.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class NEWARRAY extends Instruction implements AllocationInstruction, ExceptionThrower, + StackProducer { + + private byte type; + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + NEWARRAY() { + } + + + public NEWARRAY(byte type) { + super(org.apache.bcel.Constants.NEWARRAY, (short) 2); + this.type = type; + } + + + public NEWARRAY(BasicType type) { + this(type.getType()); + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + out.writeByte(opcode); + out.writeByte(type); + } + + + /** + * @return numeric code for basic element type + */ + public final byte getTypecode() { + return type; + } + + + /** + * @return type of constructed array + */ + public final Type getType() { + return new ArrayType(BasicType.getType(type), 1); + } + + + /** + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + return super.toString(verbose) + " " + org.apache.bcel.Constants.TYPE_NAMES[type]; + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + type = bytes.readByte(); + length = 2; + } + + + public Class[] getExceptions() { + return new Class[] { + org.apache.bcel.ExceptionConstants.NEGATIVE_ARRAY_SIZE_EXCEPTION + }; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitAllocationInstruction(this); + v.visitExceptionThrower(this); + v.visitStackProducer(this); + v.visitNEWARRAY(this); + } +} diff --git a/src/org/apache/bcel/generic/NOP.java b/src/org/apache/bcel/generic/NOP.java new file mode 100644 index 0000000..bf69664 --- /dev/null +++ b/src/org/apache/bcel/generic/NOP.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * NOP - Do nothing + * + * @version $Id: NOP.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class NOP extends Instruction { + + public NOP() { + super(org.apache.bcel.Constants.NOP, (short) 1); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitNOP(this); + } +} diff --git a/src/org/apache/bcel/generic/NamedAndTyped.java b/src/org/apache/bcel/generic/NamedAndTyped.java new file mode 100644 index 0000000..aefa3df --- /dev/null +++ b/src/org/apache/bcel/generic/NamedAndTyped.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denote entity that has both name and type. This is true for local variables, + * methods and fields. + * + * @version $Id: NamedAndTyped.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface NamedAndTyped { + + public String getName(); + + + public Type getType(); + + + public void setName( String name ); + + + public void setType( Type type ); +} diff --git a/src/org/apache/bcel/generic/ObjectType.java b/src/org/apache/bcel/generic/ObjectType.java new file mode 100644 index 0000000..2db0afa --- /dev/null +++ b/src/org/apache/bcel/generic/ObjectType.java @@ -0,0 +1,155 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.JavaClass; + +/** + * Denotes reference such as java.lang.String. + * + * @version $Id: ObjectType.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ObjectType extends ReferenceType { + + private String class_name; // Class name of type + + + /** + * @param class_name fully qualified class name, e.g. java.lang.String + */ + public ObjectType(String class_name) { + super(Constants.T_REFERENCE, "L" + class_name.replace('.', '/') + ";"); + this.class_name = class_name.replace('/', '.'); + } + + + /** @return name of referenced class + */ + public String getClassName() { + return class_name; + } + + + /** @return a hash code value for the object. + */ + public int hashCode() { + return class_name.hashCode(); + } + + + /** @return true if both type objects refer to the same class. + */ + public boolean equals( Object type ) { + return (type instanceof ObjectType) + ? ((ObjectType) type).class_name.equals(class_name) + : false; + } + + + /** + * If "this" doesn't reference a class, it references an interface + * or a non-existant entity. + * @deprecated this method returns an inaccurate result + * if the class or interface referenced cannot + * be found: use referencesClassExact() instead + */ + public boolean referencesClass() { + try { + JavaClass jc = Repository.lookupClass(class_name); + return jc.isClass(); + } catch (ClassNotFoundException e) { + return false; + } + } + + + /** + * If "this" doesn't reference an interface, it references a class + * or a non-existant entity. + * @deprecated this method returns an inaccurate result + * if the class or interface referenced cannot + * be found: use referencesInterfaceExact() instead + */ + public boolean referencesInterface() { + try { + JavaClass jc = Repository.lookupClass(class_name); + return !jc.isClass(); + } catch (ClassNotFoundException e) { + return false; + } + } + + + /** + * Return true if this type references a class, + * false if it references an interface. + * @return true if the type references a class, false if + * it references an interface + * @throws ClassNotFoundException if the class or interface + * referenced by this type can't be found + */ + public boolean referencesClassExact() throws ClassNotFoundException { + JavaClass jc = Repository.lookupClass(class_name); + return jc.isClass(); + } + + + /** + * Return true if this type references an interface, + * false if it references a class. + * @return true if the type references an interface, false if + * it references a class + * @throws ClassNotFoundException if the class or interface + * referenced by this type can't be found + */ + public boolean referencesInterfaceExact() throws ClassNotFoundException { + JavaClass jc = Repository.lookupClass(class_name); + return !jc.isClass(); + } + + + /** + * Return true if this type is a subclass of given ObjectType. + * @throws ClassNotFoundException if any of this class's superclasses + * can't be found + */ + public boolean subclassOf( ObjectType superclass ) throws ClassNotFoundException { + if (this.referencesInterface() || superclass.referencesInterface()) { + return false; + } + return Repository.instanceOf(this.class_name, superclass.class_name); + } + + + /** + * Java Virtual Machine Specification edition 2, 5.4.4 Access Control + * @throws ClassNotFoundException if the class referenced by this type + * can't be found + */ + public boolean accessibleTo( ObjectType accessor ) throws ClassNotFoundException { + JavaClass jc = Repository.lookupClass(class_name); + if (jc.isPublic()) { + return true; + } else { + JavaClass acc = Repository.lookupClass(accessor.class_name); + return acc.getPackageName().equals(jc.getPackageName()); + } + } +} diff --git a/src/org/apache/bcel/generic/POP.java b/src/org/apache/bcel/generic/POP.java new file mode 100644 index 0000000..0d8c672 --- /dev/null +++ b/src/org/apache/bcel/generic/POP.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * POP - Pop top operand stack word + * + *
      Stack: ..., word -> ...
      + * + * @version $Id: POP.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class POP extends StackInstruction implements PopInstruction { + + public POP() { + super(org.apache.bcel.Constants.POP); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitPopInstruction(this); + v.visitStackInstruction(this); + v.visitPOP(this); + } +} diff --git a/src/org/apache/bcel/generic/POP2.java b/src/org/apache/bcel/generic/POP2.java new file mode 100644 index 0000000..20b4e7a --- /dev/null +++ b/src/org/apache/bcel/generic/POP2.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * POP2 - Pop two top operand stack words + * + *
      Stack: ..., word2, word1 -> ...
      + * + * @version $Id: POP2.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class POP2 extends StackInstruction implements PopInstruction { + + public POP2() { + super(org.apache.bcel.Constants.POP2); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitPopInstruction(this); + v.visitStackInstruction(this); + v.visitPOP2(this); + } +} diff --git a/src/org/apache/bcel/generic/PUSH.java b/src/org/apache/bcel/generic/PUSH.java new file mode 100644 index 0000000..3759d13 --- /dev/null +++ b/src/org/apache/bcel/generic/PUSH.java @@ -0,0 +1,178 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; + +/** + * Wrapper class for push operations, which are implemented either as BIPUSH, + * LDC or xCONST_n instructions. + * + * @version $Id: PUSH.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class PUSH implements CompoundInstruction, VariableLengthInstruction, + InstructionConstants { + + private Instruction instruction; + + + /** + * This constructor also applies for values of type short, char, byte + * + * @param cp Constant pool + * @param value to be pushed + */ + public PUSH(ConstantPoolGen cp, int value) { + if ((value >= -1) && (value <= 5)) { + instruction = INSTRUCTIONS[Constants.ICONST_0 + value]; + } else if ((value >= -128) && (value <= 127)) { + instruction = new BIPUSH((byte) value); + } else if ((value >= -32768) && (value <= 32767)) { + instruction = new SIPUSH((short) value); + } else { + instruction = new LDC(cp.addInteger(value)); + } + } + + + /** + * @param cp Constant pool + * @param value to be pushed + */ + public PUSH(ConstantPoolGen cp, boolean value) { + instruction = INSTRUCTIONS[Constants.ICONST_0 + (value ? 1 : 0)]; + } + + + /** + * @param cp Constant pool + * @param value to be pushed + */ + public PUSH(ConstantPoolGen cp, float value) { + if (value == 0.0) { + instruction = FCONST_0; + } else if (value == 1.0) { + instruction = FCONST_1; + } else if (value == 2.0) { + instruction = FCONST_2; + } else { + instruction = new LDC(cp.addFloat(value)); + } + } + + + /** + * @param cp Constant pool + * @param value to be pushed + */ + public PUSH(ConstantPoolGen cp, long value) { + if (value == 0) { + instruction = LCONST_0; + } else if (value == 1) { + instruction = LCONST_1; + } else { + instruction = new LDC2_W(cp.addLong(value)); + } + } + + + /** + * @param cp Constant pool + * @param value to be pushed + */ + public PUSH(ConstantPoolGen cp, double value) { + if (value == 0.0) { + instruction = DCONST_0; + } else if (value == 1.0) { + instruction = DCONST_1; + } else { + instruction = new LDC2_W(cp.addDouble(value)); + } + } + + + /** + * @param cp Constant pool + * @param value to be pushed + */ + public PUSH(ConstantPoolGen cp, String value) { + if (value == null) { + instruction = ACONST_NULL; + } else { + instruction = new LDC(cp.addString(value)); + } + } + + + /** + * @param cp Constant pool + * @param value to be pushed + */ + public PUSH(ConstantPoolGen cp, Number value) { + if ((value instanceof Integer) || (value instanceof Short) || (value instanceof Byte)) { + instruction = new PUSH(cp, value.intValue()).instruction; + } else if (value instanceof Double) { + instruction = new PUSH(cp, value.doubleValue()).instruction; + } else if (value instanceof Float) { + instruction = new PUSH(cp, value.floatValue()).instruction; + } else if (value instanceof Long) { + instruction = new PUSH(cp, value.longValue()).instruction; + } else { + throw new ClassGenException("What's this: " + value); + } + } + + + /** + * creates a push object from a Character value. Warning: Make sure not to attempt to allow + * autoboxing to create this value parameter, as an alternative constructor will be called + * + * @param cp Constant pool + * @param value to be pushed + */ + public PUSH(ConstantPoolGen cp, Character value) { + this(cp, value.charValue()); + } + + + /** + * @param cp Constant pool + * @param value to be pushed + */ + public PUSH(ConstantPoolGen cp, Boolean value) { + this(cp, value.booleanValue()); + } + + + public final InstructionList getInstructionList() { + return new InstructionList(instruction); + } + + + public final Instruction getInstruction() { + return instruction; + } + + + /** + * @return mnemonic for instruction + */ + public String toString() { + return instruction.toString() + " (PUSH)"; + } +} diff --git a/src/org/apache/bcel/generic/PUTFIELD.java b/src/org/apache/bcel/generic/PUTFIELD.java new file mode 100644 index 0000000..6c5b28a --- /dev/null +++ b/src/org/apache/bcel/generic/PUTFIELD.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.ExceptionConstants; + +/** + * PUTFIELD - Put field in object + *
      Stack: ..., objectref, value -> ...
      + * OR + *
      Stack: ..., objectref, value.word1, value.word2 -> ...
      + * + * @version $Id: PUTFIELD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class PUTFIELD extends FieldInstruction implements PopInstruction, ExceptionThrower { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + PUTFIELD() { + } + + + public PUTFIELD(int index) { + super(Constants.PUTFIELD, index); + } + + + public int consumeStack( ConstantPoolGen cpg ) { + return getFieldSize(cpg) + 1; + } + + + public Class[] getExceptions() { + Class[] cs = new Class[2 + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length); + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length + 1] = ExceptionConstants.INCOMPATIBLE_CLASS_CHANGE_ERROR; + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length] = ExceptionConstants.NULL_POINTER_EXCEPTION; + return cs; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitStackConsumer(this); + v.visitPopInstruction(this); + v.visitTypedInstruction(this); + v.visitLoadClass(this); + v.visitCPInstruction(this); + v.visitFieldOrMethod(this); + v.visitFieldInstruction(this); + v.visitPUTFIELD(this); + } +} diff --git a/src/org/apache/bcel/generic/PUTSTATIC.java b/src/org/apache/bcel/generic/PUTSTATIC.java new file mode 100644 index 0000000..5afd569 --- /dev/null +++ b/src/org/apache/bcel/generic/PUTSTATIC.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.ExceptionConstants; + +/** + * PUTSTATIC - Put static field in class + *
      Stack: ..., value -> ...
      + * OR + *
      Stack: ..., value.word1, value.word2 -> ...
      + * + * @version $Id: PUTSTATIC.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class PUTSTATIC extends FieldInstruction implements ExceptionThrower, PopInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + PUTSTATIC() { + } + + + public PUTSTATIC(int index) { + super(Constants.PUTSTATIC, index); + } + + + public int consumeStack( ConstantPoolGen cpg ) { + return getFieldSize(cpg); + } + + + public Class[] getExceptions() { + Class[] cs = new Class[1 + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length]; + System.arraycopy(ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION, 0, cs, 0, + ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length); + cs[ExceptionConstants.EXCS_FIELD_AND_METHOD_RESOLUTION.length] = ExceptionConstants.INCOMPATIBLE_CLASS_CHANGE_ERROR; + return cs; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitStackConsumer(this); + v.visitPopInstruction(this); + v.visitTypedInstruction(this); + v.visitLoadClass(this); + v.visitCPInstruction(this); + v.visitFieldOrMethod(this); + v.visitFieldInstruction(this); + v.visitPUTSTATIC(this); + } +} diff --git a/src/org/apache/bcel/generic/PopInstruction.java b/src/org/apache/bcel/generic/PopInstruction.java new file mode 100644 index 0000000..65c81ee --- /dev/null +++ b/src/org/apache/bcel/generic/PopInstruction.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denotes an unparameterized instruction to pop a value on top from the stack, + * such as ISTORE, POP, PUTSTATIC. + * + * @version $Id: PopInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see ISTORE + * @see POP + */ +public interface PopInstruction extends StackConsumer { +} diff --git a/src/org/apache/bcel/generic/PushInstruction.java b/src/org/apache/bcel/generic/PushInstruction.java new file mode 100644 index 0000000..8a74105 --- /dev/null +++ b/src/org/apache/bcel/generic/PushInstruction.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denotes an unparameterized instruction to produce a value on top of the stack, + * such as ILOAD, LDC, SIPUSH, DUP, ICONST, etc. + * + * @version $Id: PushInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + + * @see ILOAD + * @see ICONST + * @see LDC + * @see DUP + * @see SIPUSH + * @see GETSTATIC + */ +public interface PushInstruction extends StackProducer { +} diff --git a/src/org/apache/bcel/generic/RET.java b/src/org/apache/bcel/generic/RET.java new file mode 100644 index 0000000..2182d36 --- /dev/null +++ b/src/org/apache/bcel/generic/RET.java @@ -0,0 +1,139 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * RET - Return from subroutine + * + *
      Stack: ... -> ...
      + * + * @version $Id: RET.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class RET extends Instruction implements IndexedInstruction, TypedInstruction { + + private boolean wide; + private int index; // index to local variable containg the return address + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + RET() { + } + + + public RET(int index) { + super(org.apache.bcel.Constants.RET, (short) 2); + setIndex(index); // May set wide as side effect + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + if (wide) { + out.writeByte(org.apache.bcel.Constants.WIDE); + } + out.writeByte(opcode); + if (wide) { + out.writeShort(index); + } else { + out.writeByte(index); + } + } + + + private final void setWide() { + wide = index > org.apache.bcel.Constants.MAX_BYTE; + if (wide) { + length = 4; // Including the wide byte + } else { + length = 2; + } + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + this.wide = wide; + if (wide) { + index = bytes.readUnsignedShort(); + length = 4; + } else { + index = bytes.readUnsignedByte(); + length = 2; + } + } + + + /** + * @return index of local variable containg the return address + */ + public final int getIndex() { + return index; + } + + + /** + * Set index of local variable containg the return address + */ + public final void setIndex( int n ) { + if (n < 0) { + throw new ClassGenException("Negative index value: " + n); + } + index = n; + setWide(); + } + + + /** + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + return super.toString(verbose) + " " + index; + } + + + /** @return return address type + */ + public Type getType( ConstantPoolGen cp ) { + return ReturnaddressType.NO_TARGET; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitRET(this); + } +} diff --git a/src/org/apache/bcel/generic/RETURN.java b/src/org/apache/bcel/generic/RETURN.java new file mode 100644 index 0000000..3e71689 --- /dev/null +++ b/src/org/apache/bcel/generic/RETURN.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * RETURN - Return from void method + *
      Stack: ... -> <empty>
      + * + * @version $Id: RETURN.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class RETURN extends ReturnInstruction { + + public RETURN() { + super(org.apache.bcel.Constants.RETURN); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitReturnInstruction(this); + v.visitRETURN(this); + } +} diff --git a/src/org/apache/bcel/generic/ReferenceType.java b/src/org/apache/bcel/generic/ReferenceType.java new file mode 100644 index 0000000..605b6e3 --- /dev/null +++ b/src/org/apache/bcel/generic/ReferenceType.java @@ -0,0 +1,330 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.JavaClass; + +/** + * Super class for object and array types. + * + * @version $Id: ReferenceType.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class ReferenceType extends Type { + + protected ReferenceType(byte t, String s) { + super(t, s); + } + + + /** Class is non-abstract but not instantiable from the outside + */ + ReferenceType() { + super(Constants.T_OBJECT, ""); + } + + + /** + * Return true iff this type is castable to another type t as defined in + * the JVM specification. The case where this is Type.NULL is not + * defined (see the CHECKCAST definition in the JVM specification). + * However, because e.g. CHECKCAST doesn't throw a + * ClassCastException when casting a null reference to any Object, + * true is returned in this case. + * + * @throws ClassNotFoundException if any classes or interfaces required + * to determine assignment compatibility can't be found + */ + public boolean isCastableTo( Type t ) throws ClassNotFoundException { + if (this.equals(Type.NULL)) { + return true; // If this is ever changed in isAssignmentCompatible() + } + return isAssignmentCompatibleWith(t); + /* Yes, it's true: It's the same definition. + * See vmspec2 AASTORE / CHECKCAST definitions. + */ + } + + + /** + * Return true iff this is assignment compatible with another type t + * as defined in the JVM specification; see the AASTORE definition + * there. + * @throws ClassNotFoundException if any classes or interfaces required + * to determine assignment compatibility can't be found + */ + public boolean isAssignmentCompatibleWith( Type t ) throws ClassNotFoundException { + if (!(t instanceof ReferenceType)) { + return false; + } + ReferenceType T = (ReferenceType) t; + if (this.equals(Type.NULL)) { + return true; // This is not explicitely stated, but clear. Isn't it? + } + /* If this is a class type then + */ + if ((this instanceof ObjectType) && (((ObjectType) this).referencesClassExact())) { + /* If T is a class type, then this must be the same class as T, + or this must be a subclass of T; + */ + if ((T instanceof ObjectType) && (((ObjectType) T).referencesClassExact())) { + if (this.equals(T)) { + return true; + } + if (Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T) + .getClassName())) { + return true; + } + } + /* If T is an interface type, this must implement interface T. + */ + if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterfaceExact())) { + if (Repository.implementationOf(((ObjectType) this).getClassName(), + ((ObjectType) T).getClassName())) { + return true; + } + } + } + /* If this is an interface type, then: + */ + if ((this instanceof ObjectType) && (((ObjectType) this).referencesInterfaceExact())) { + /* If T is a class type, then T must be Object (2.4.7). + */ + if ((T instanceof ObjectType) && (((ObjectType) T).referencesClassExact())) { + if (T.equals(Type.OBJECT)) { + return true; + } + } + /* If T is an interface type, then T must be the same interface + * as this or a superinterface of this (2.13.2). + */ + if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterfaceExact())) { + if (this.equals(T)) { + return true; + } + if (Repository.implementationOf(((ObjectType) this).getClassName(), + ((ObjectType) T).getClassName())) { + return true; + } + } + } + /* If this is an array type, namely, the type SC[], that is, an + * array of components of type SC, then: + */ + if (this instanceof ArrayType) { + /* If T is a class type, then T must be Object (�2.4.7). + */ + if ((T instanceof ObjectType) && (((ObjectType) T).referencesClassExact())) { + if (T.equals(Type.OBJECT)) { + return true; + } + } + /* If T is an array type TC[], that is, an array of components + * of type TC, then one of the following must be true: + */ + if (T instanceof ArrayType) { + /* TC and SC are the same primitive type (�2.4.1). + */ + Type sc = ((ArrayType) this).getElementType(); + Type tc = ((ArrayType) T).getElementType(); + if (sc instanceof BasicType && tc instanceof BasicType && sc.equals(tc)) { + return true; + } + /* TC and SC are reference types (�2.4.6), and type SC is + * assignable to TC by these runtime rules. + */ + if (tc instanceof ReferenceType && sc instanceof ReferenceType + && ((ReferenceType) sc).isAssignmentCompatibleWith(tc)) { + return true; + } + } + /* If T is an interface type, T must be one of the interfaces implemented by arrays (�2.15). */ + // TODO: Check if this is still valid or find a way to dynamically find out which + // interfaces arrays implement. However, as of the JVM specification edition 2, there + // are at least two different pages where assignment compatibility is defined and + // on one of them "interfaces implemented by arrays" is exchanged with "'Cloneable' or + // 'java.io.Serializable'" + if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterfaceExact())) { + for (int ii = 0; ii < Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS.length; ii++) { + if (T.equals(new ObjectType(Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS[ii]))) { + return true; + } + } + } + } + return false; // default. + } + + + /** + * This commutative operation returns the first common superclass (narrowest ReferenceType + * referencing a class, not an interface). + * If one of the types is a superclass of the other, the former is returned. + * If "this" is Type.NULL, then t is returned. + * If t is Type.NULL, then "this" is returned. + * If "this" equals t ['this.equals(t)'] "this" is returned. + * If "this" or t is an ArrayType, then Type.OBJECT is returned; + * unless their dimensions match. Then an ArrayType of the same + * number of dimensions is returned, with its basic type being the + * first common super class of the basic types of "this" and t. + * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. + * If not all of the two classes' superclasses cannot be found, "null" is returned. + * See the JVM specification edition 2, "�4.9.2 The Bytecode Verifier". + * + * @throws ClassNotFoundException on failure to find superclasses of this + * type, or the type passed as a parameter + */ + public ReferenceType getFirstCommonSuperclass( ReferenceType t ) throws ClassNotFoundException { + if (this.equals(Type.NULL)) { + return t; + } + if (t.equals(Type.NULL)) { + return this; + } + if (this.equals(t)) { + return this; + /* + * TODO: Above sounds a little arbitrary. On the other hand, there is + * no object referenced by Type.NULL so we can also say all the objects + * referenced by Type.NULL were derived from java.lang.Object. + * However, the Java Language's "instanceof" operator proves us wrong: + * "null" is not referring to an instance of java.lang.Object :) + */ + } + /* This code is from a bug report by Konstantin Shagin */ + if ((this instanceof ArrayType) && (t instanceof ArrayType)) { + ArrayType arrType1 = (ArrayType) this; + ArrayType arrType2 = (ArrayType) t; + if ((arrType1.getDimensions() == arrType2.getDimensions()) + && arrType1.getBasicType() instanceof ObjectType + && arrType2.getBasicType() instanceof ObjectType) { + return new ArrayType(((ObjectType) arrType1.getBasicType()) + .getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()), arrType1 + .getDimensions()); + } + } + if ((this instanceof ArrayType) || (t instanceof ArrayType)) { + return Type.OBJECT; + // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? + } + if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) + || ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) { + return Type.OBJECT; + // TODO: The above line is correct comparing to the vmspec2. But one could + // make class file verification a bit stronger here by using the notion of + // superinterfaces or even castability or assignment compatibility. + } + // this and t are ObjectTypes, see above. + ObjectType thiz = (ObjectType) this; + ObjectType other = (ObjectType) t; + JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); + JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); + if ((thiz_sups == null) || (other_sups == null)) { + return null; + } + // Waaahh... + JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; + JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; + System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); + System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); + this_sups[0] = Repository.lookupClass(thiz.getClassName()); + t_sups[0] = Repository.lookupClass(other.getClassName()); + for (int i = 0; i < t_sups.length; i++) { + for (int j = 0; j < this_sups.length; j++) { + if (this_sups[j].equals(t_sups[i])) { + return new ObjectType(this_sups[j].getClassName()); + } + } + } + // Huh? Did you ask for Type.OBJECT's superclass?? + return null; + } + + + /** + * This commutative operation returns the first common superclass (narrowest ReferenceType + * referencing a class, not an interface). + * If one of the types is a superclass of the other, the former is returned. + * If "this" is Type.NULL, then t is returned. + * If t is Type.NULL, then "this" is returned. + * If "this" equals t ['this.equals(t)'] "this" is returned. + * If "this" or t is an ArrayType, then Type.OBJECT is returned. + * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. + * If not all of the two classes' superclasses cannot be found, "null" is returned. + * See the JVM specification edition 2, "�4.9.2 The Bytecode Verifier". + * + * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has + * slightly changed semantics. + * @throws ClassNotFoundException on failure to find superclasses of this + * type, or the type passed as a parameter + */ + public ReferenceType firstCommonSuperclass( ReferenceType t ) throws ClassNotFoundException { + if (this.equals(Type.NULL)) { + return t; + } + if (t.equals(Type.NULL)) { + return this; + } + if (this.equals(t)) { + return this; + /* + * TODO: Above sounds a little arbitrary. On the other hand, there is + * no object referenced by Type.NULL so we can also say all the objects + * referenced by Type.NULL were derived from java.lang.Object. + * However, the Java Language's "instanceof" operator proves us wrong: + * "null" is not referring to an instance of java.lang.Object :) + */ + } + if ((this instanceof ArrayType) || (t instanceof ArrayType)) { + return Type.OBJECT; + // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? + } + if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) + || ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) { + return Type.OBJECT; + // TODO: The above line is correct comparing to the vmspec2. But one could + // make class file verification a bit stronger here by using the notion of + // superinterfaces or even castability or assignment compatibility. + } + // this and t are ObjectTypes, see above. + ObjectType thiz = (ObjectType) this; + ObjectType other = (ObjectType) t; + JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); + JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); + if ((thiz_sups == null) || (other_sups == null)) { + return null; + } + // Waaahh... + JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; + JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; + System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); + System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); + this_sups[0] = Repository.lookupClass(thiz.getClassName()); + t_sups[0] = Repository.lookupClass(other.getClassName()); + for (int i = 0; i < t_sups.length; i++) { + for (int j = 0; j < this_sups.length; j++) { + if (this_sups[j].equals(t_sups[i])) { + return new ObjectType(this_sups[j].getClassName()); + } + } + } + // Huh? Did you ask for Type.OBJECT's superclass?? + return null; + } +} diff --git a/src/org/apache/bcel/generic/ReturnInstruction.java b/src/org/apache/bcel/generic/ReturnInstruction.java new file mode 100644 index 0000000..cb10a12 --- /dev/null +++ b/src/org/apache/bcel/generic/ReturnInstruction.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; +import org.apache.bcel.ExceptionConstants; + +/** + * Super class for the xRETURN family of instructions. + * + * @version $Id: ReturnInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class ReturnInstruction extends Instruction implements ExceptionThrower, + TypedInstruction, StackConsumer { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + ReturnInstruction() { + } + + + /** + * @param opcode of instruction + */ + protected ReturnInstruction(short opcode) { + super(opcode, (short) 1); + } + + + public Type getType() { + switch (opcode) { + case Constants.IRETURN: + return Type.INT; + case Constants.LRETURN: + return Type.LONG; + case Constants.FRETURN: + return Type.FLOAT; + case Constants.DRETURN: + return Type.DOUBLE; + case Constants.ARETURN: + return Type.OBJECT; + case Constants.RETURN: + return Type.VOID; + default: // Never reached + throw new ClassGenException("Unknown type " + opcode); + } + } + + + public Class[] getExceptions() { + return new Class[] { + ExceptionConstants.ILLEGAL_MONITOR_STATE + }; + } + + + /** @return type associated with the instruction + */ + public Type getType( ConstantPoolGen cp ) { + return getType(); + } +} diff --git a/src/org/apache/bcel/generic/ReturnaddressType.java b/src/org/apache/bcel/generic/ReturnaddressType.java new file mode 100644 index 0000000..6b272dd --- /dev/null +++ b/src/org/apache/bcel/generic/ReturnaddressType.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import org.apache.bcel.Constants; + +/** + * Returnaddress, the type JSR or JSR_W instructions push upon the stack. + * + * see vmspec2 3.3.3 + * @version $Id: ReturnaddressType.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public class ReturnaddressType extends Type { + + public static final ReturnaddressType NO_TARGET = new ReturnaddressType(); + private InstructionHandle returnTarget; + + + /** + * A Returnaddress [that doesn't know where to return to]. + */ + private ReturnaddressType() { + super(Constants.T_ADDRESS, ""); + } + + + /** + * Creates a ReturnaddressType object with a target. + */ + public ReturnaddressType(InstructionHandle returnTarget) { + super(Constants.T_ADDRESS, ""); + this.returnTarget = returnTarget; + } + + + /** @return a hash code value for the object. + */ + public int hashCode() { + if (returnTarget == null) { + return 0; + } + return returnTarget.hashCode(); + } + + + /** + * Returns if the two Returnaddresses refer to the same target. + */ + public boolean equals( Object rat ) { + if (!(rat instanceof ReturnaddressType)) { + return false; + } + ReturnaddressType that = (ReturnaddressType) rat; + if (this.returnTarget == null || that.returnTarget == null) { + return that.returnTarget == this.returnTarget; + } + return that.returnTarget.equals(this.returnTarget); + } + + + /** + * @return the target of this ReturnaddressType + */ + public InstructionHandle getTarget() { + return returnTarget; + } +} diff --git a/src/org/apache/bcel/generic/SALOAD.java b/src/org/apache/bcel/generic/SALOAD.java new file mode 100644 index 0000000..0665469 --- /dev/null +++ b/src/org/apache/bcel/generic/SALOAD.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * SALOAD - Load short from array + *
      Stack: ..., arrayref, index -> ..., value
      + * + * @version $Id: SALOAD.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class SALOAD extends ArrayInstruction implements StackProducer { + + public SALOAD() { + super(org.apache.bcel.Constants.SALOAD); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackProducer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitSALOAD(this); + } +} diff --git a/src/org/apache/bcel/generic/SASTORE.java b/src/org/apache/bcel/generic/SASTORE.java new file mode 100644 index 0000000..164ee44 --- /dev/null +++ b/src/org/apache/bcel/generic/SASTORE.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * SASTORE - Store into short array + *
      Stack: ..., arrayref, index, value -> ...
      + * + * @version $Id: SASTORE.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class SASTORE extends ArrayInstruction implements StackConsumer { + + public SASTORE() { + super(org.apache.bcel.Constants.SASTORE); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitArrayInstruction(this); + v.visitSASTORE(this); + } +} diff --git a/src/org/apache/bcel/generic/SIPUSH.java b/src/org/apache/bcel/generic/SIPUSH.java new file mode 100644 index 0000000..45cdce0 --- /dev/null +++ b/src/org/apache/bcel/generic/SIPUSH.java @@ -0,0 +1,103 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * SIPUSH - Push short + * + *
      Stack: ... -> ..., value
      + * + * @version $Id: SIPUSH.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class SIPUSH extends Instruction implements ConstantPushInstruction { + + private short b; + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + SIPUSH() { + } + + + public SIPUSH(short b) { + super(org.apache.bcel.Constants.SIPUSH, (short) 3); + this.b = b; + } + + + /** + * Dump instruction as short code to stream out. + */ + public void dump( DataOutputStream out ) throws IOException { + super.dump(out); + out.writeShort(b); + } + + + /** + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + return super.toString(verbose) + " " + b; + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + length = 3; + b = bytes.readShort(); + } + + + public Number getValue() { + return new Integer(b); + } + + + /** @return Type.SHORT + */ + public Type getType( ConstantPoolGen cp ) { + return Type.SHORT; + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitPushInstruction(this); + v.visitStackProducer(this); + v.visitTypedInstruction(this); + v.visitConstantPushInstruction(this); + v.visitSIPUSH(this); + } +} diff --git a/src/org/apache/bcel/generic/SWAP.java b/src/org/apache/bcel/generic/SWAP.java new file mode 100644 index 0000000..a58e6fb --- /dev/null +++ b/src/org/apache/bcel/generic/SWAP.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * SWAP - Swa top operand stack word + *
      Stack: ..., word2, word1 -> ..., word1, word2
      + * + * @version $Id: SWAP.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class SWAP extends StackInstruction implements StackConsumer, StackProducer { + + public SWAP() { + super(org.apache.bcel.Constants.SWAP); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitStackProducer(this); + v.visitStackInstruction(this); + v.visitSWAP(this); + } +} diff --git a/src/org/apache/bcel/generic/SWITCH.java b/src/org/apache/bcel/generic/SWITCH.java new file mode 100644 index 0000000..01982fa --- /dev/null +++ b/src/org/apache/bcel/generic/SWITCH.java @@ -0,0 +1,153 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * SWITCH - Branch depending on int value, generates either LOOKUPSWITCH or + * TABLESWITCH instruction, depending on whether the match values (int[]) can be + * sorted with no gaps between the numbers. + * + * @version $Id: SWITCH.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class SWITCH implements CompoundInstruction { + + private int[] match; + private InstructionHandle[] targets; + private Select instruction; + private int match_length; + + + /** + * Template for switch() constructs. If the match array can be + * sorted in ascending order with gaps no larger than max_gap + * between the numbers, a TABLESWITCH instruction is generated, and + * a LOOKUPSWITCH otherwise. The former may be more efficient, but + * needs more space. + * + * Note, that the key array always will be sorted, though we leave + * the original arrays unaltered. + * + * @param match array of match values (case 2: ... case 7: ..., etc.) + * @param targets the instructions to be branched to for each case + * @param target the default target + * @param max_gap maximum gap that may between case branches + */ + public SWITCH(int[] match, InstructionHandle[] targets, InstructionHandle target, int max_gap) { + this.match = (int[]) match.clone(); + this.targets = (InstructionHandle[]) targets.clone(); + if ((match_length = match.length) < 2) { + instruction = new TABLESWITCH(match, targets, target); + } else { + sort(0, match_length - 1); + if (matchIsOrdered(max_gap)) { + fillup(max_gap, target); + instruction = new TABLESWITCH(this.match, this.targets, target); + } else { + instruction = new LOOKUPSWITCH(this.match, this.targets, target); + } + } + } + + + public SWITCH(int[] match, InstructionHandle[] targets, InstructionHandle target) { + this(match, targets, target, 1); + } + + + private final void fillup( int max_gap, InstructionHandle target ) { + int max_size = match_length + match_length * max_gap; + int[] m_vec = new int[max_size]; + InstructionHandle[] t_vec = new InstructionHandle[max_size]; + int count = 1; + m_vec[0] = match[0]; + t_vec[0] = targets[0]; + for (int i = 1; i < match_length; i++) { + int prev = match[i - 1]; + int gap = match[i] - prev; + for (int j = 1; j < gap; j++) { + m_vec[count] = prev + j; + t_vec[count] = target; + count++; + } + m_vec[count] = match[i]; + t_vec[count] = targets[i]; + count++; + } + match = new int[count]; + targets = new InstructionHandle[count]; + System.arraycopy(m_vec, 0, match, 0, count); + System.arraycopy(t_vec, 0, targets, 0, count); + } + + + /** + * Sort match and targets array with QuickSort. + */ + private final void sort( int l, int r ) { + int i = l, j = r; + int h, m = match[(l + r) / 2]; + InstructionHandle h2; + do { + while (match[i] < m) { + i++; + } + while (m < match[j]) { + j--; + } + if (i <= j) { + h = match[i]; + match[i] = match[j]; + match[j] = h; // Swap elements + h2 = targets[i]; + targets[i] = targets[j]; + targets[j] = h2; // Swap instructions, too + i++; + j--; + } + } while (i <= j); + if (l < j) { + sort(l, j); + } + if (i < r) { + sort(i, r); + } + } + + + /** + * @return match is sorted in ascending order with no gap bigger than max_gap? + */ + private final boolean matchIsOrdered( int max_gap ) { + for (int i = 1; i < match_length; i++) { + if (match[i] - match[i - 1] > max_gap) { + return false; + } + } + return true; + } + + + public final InstructionList getInstructionList() { + return new InstructionList(instruction); + } + + + public final Instruction getInstruction() { + return instruction; + } +} diff --git a/src/org/apache/bcel/generic/Select.java b/src/org/apache/bcel/generic/Select.java new file mode 100644 index 0000000..213a674 --- /dev/null +++ b/src/org/apache/bcel/generic/Select.java @@ -0,0 +1,236 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * Select - Abstract super class for LOOKUPSWITCH and TABLESWITCH instructions. + * + *

      We use our super's target property as the default target. + * + * @version $Id: Select.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see LOOKUPSWITCH + * @see TABLESWITCH + * @see InstructionList + */ +public abstract class Select extends BranchInstruction implements VariableLengthInstruction, + StackProducer { + + protected int[] match; // matches, i.e., case 1: ... + protected int[] indices; // target offsets + protected InstructionHandle[] targets; // target objects in instruction list + protected int fixed_length; // fixed length defined by subclasses + protected int match_length; // number of cases + protected int padding = 0; // number of pad bytes for alignment + + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + Select() { + } + + + /** + * (Match, target) pairs for switch. + * `Match' and `targets' must have the same length of course. + * + * @param match array of matching values + * @param targets instruction targets + * @param defaultTarget default instruction target + */ + Select(short opcode, int[] match, InstructionHandle[] targets, InstructionHandle defaultTarget) { + super(opcode, defaultTarget); + this.targets = targets; + for (int i = 0; i < targets.length; i++) { + notifyTarget(null, targets[i], this); + } + this.match = match; + if ((match_length = match.length) != targets.length) { + throw new ClassGenException("Match and target array have not the same length"); + } + indices = new int[match_length]; + } + + + /** + * Since this is a variable length instruction, it may shift the following + * instructions which then need to update their position. + * + * Called by InstructionList.setPositions when setting the position for every + * instruction. In the presence of variable length instructions `setPositions' + * performs multiple passes over the instruction list to calculate the + * correct (byte) positions and offsets by calling this function. + * + * @param offset additional offset caused by preceding (variable length) instructions + * @param max_offset the maximum offset that may be caused by these instructions + * @return additional offset caused by possible change of this instruction's length + */ + protected int updatePosition( int offset, int max_offset ) { + position += offset; // Additional offset caused by preceding SWITCHs, GOTOs, etc. + short old_length = length; + /* Alignment on 4-byte-boundary, + 1, because of tag byte. + */ + padding = (4 - ((position + 1) % 4)) % 4; + length = (short) (fixed_length + padding); // Update length + return length - old_length; + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + out.writeByte(opcode); + for (int i = 0; i < padding; i++) { + out.writeByte(0); + } + index = getTargetOffset(); // Write default target offset + out.writeInt(index); + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + padding = (4 - (bytes.getIndex() % 4)) % 4; // Compute number of pad bytes + for (int i = 0; i < padding; i++) { + bytes.readByte(); + } + // Default branch target common for both cases (TABLESWITCH, LOOKUPSWITCH) + index = bytes.readInt(); + } + + + /** + * @return mnemonic for instruction + */ + public String toString( boolean verbose ) { + StringBuffer buf = new StringBuffer(super.toString(verbose)); + if (verbose) { + for (int i = 0; i < match_length; i++) { + String s = "null"; + if (targets[i] != null) { + s = targets[i].getInstruction().toString(); + } + buf.append("(").append(match[i]).append(", ").append(s).append(" = {").append( + indices[i]).append("})"); + } + } else { + buf.append(" ..."); + } + return buf.toString(); + } + + + /** + * Set branch target for `i'th case + */ + public void setTarget( int i, InstructionHandle target ) { + notifyTarget(targets[i], target, this); + targets[i] = target; + } + + + /** + * @param old_ih old target + * @param new_ih new target + */ + public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ) { + boolean targeted = false; + if (target == old_ih) { + targeted = true; + setTarget(new_ih); + } + for (int i = 0; i < targets.length; i++) { + if (targets[i] == old_ih) { + targeted = true; + setTarget(i, new_ih); + } + } + if (!targeted) { + throw new ClassGenException("Not targeting " + old_ih); + } + } + + + /** + * @return true, if ih is target of this instruction + */ + public boolean containsTarget( InstructionHandle ih ) { + if (target == ih) { + return true; + } + for (int i = 0; i < targets.length; i++) { + if (targets[i] == ih) { + return true; + } + } + return false; + } + + + protected Object clone() throws CloneNotSupportedException { + Select copy = (Select) super.clone(); + copy.match = (int[]) match.clone(); + copy.indices = (int[]) indices.clone(); + copy.targets = (InstructionHandle[]) targets.clone(); + return copy; + } + + + /** + * Inform targets that they're not targeted anymore. + */ + void dispose() { + super.dispose(); + for (int i = 0; i < targets.length; i++) { + targets[i].removeTargeter(this); + } + } + + + /** + * @return array of match indices + */ + public int[] getMatchs() { + return match; + } + + + /** + * @return array of match target offsets + */ + public int[] getIndices() { + return indices; + } + + + /** + * @return array of match targets + */ + public InstructionHandle[] getTargets() { + return targets; + } +} diff --git a/src/org/apache/bcel/generic/StackConsumer.java b/src/org/apache/bcel/generic/StackConsumer.java new file mode 100644 index 0000000..a7689fa --- /dev/null +++ b/src/org/apache/bcel/generic/StackConsumer.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denote an instruction that may consume a value from the stack. + * + * @version $Id: StackConsumer.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface StackConsumer { + + /** @return how many words are consumed from stack + */ + public int consumeStack( ConstantPoolGen cpg ); +} diff --git a/src/org/apache/bcel/generic/StackInstruction.java b/src/org/apache/bcel/generic/StackInstruction.java new file mode 100644 index 0000000..1b232b7 --- /dev/null +++ b/src/org/apache/bcel/generic/StackInstruction.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Super class for stack operations like DUP and POP. + * + * @version $Id: StackInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class StackInstruction extends Instruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + StackInstruction() { + } + + + /** + * @param opcode instruction opcode + */ + protected StackInstruction(short opcode) { + super(opcode, (short) 1); + } + + + /** @return Type.UNKNOWN + */ + public Type getType( ConstantPoolGen cp ) { + return Type.UNKNOWN; + } +} diff --git a/src/org/apache/bcel/generic/StackProducer.java b/src/org/apache/bcel/generic/StackProducer.java new file mode 100644 index 0000000..dab3fd8 --- /dev/null +++ b/src/org/apache/bcel/generic/StackProducer.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denote an instruction that may produce a value on top of the stack + * (this excludes DUP_X1, e.g.) + * + * @version $Id: StackProducer.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface StackProducer { + + /** @return how many words are produced on stack + */ + public int produceStack( ConstantPoolGen cpg ); +} diff --git a/src/org/apache/bcel/generic/StoreInstruction.java b/src/org/apache/bcel/generic/StoreInstruction.java new file mode 100644 index 0000000..0dc2e6f --- /dev/null +++ b/src/org/apache/bcel/generic/StoreInstruction.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denotes an unparameterized instruction to store a value into a local variable, + * e.g. ISTORE. + * + * @version $Id: StoreInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public abstract class StoreInstruction extends LocalVariableInstruction implements PopInstruction { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + * tag and length are defined in readInstruction and initFromFile, respectively. + */ + StoreInstruction(short canon_tag, short c_tag) { + super(canon_tag, c_tag); + } + + + /** + * @param opcode Instruction opcode + * @param c_tag Instruction number for compact version, ASTORE_0, e.g. + * @param n local variable index (unsigned short) + */ + protected StoreInstruction(short opcode, short c_tag, int n) { + super(opcode, c_tag, n); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitStackConsumer(this); + v.visitPopInstruction(this); + v.visitTypedInstruction(this); + v.visitLocalVariableInstruction(this); + v.visitStoreInstruction(this); + } +} diff --git a/src/org/apache/bcel/generic/TABLESWITCH.java b/src/org/apache/bcel/generic/TABLESWITCH.java new file mode 100644 index 0000000..58f2d49 --- /dev/null +++ b/src/org/apache/bcel/generic/TABLESWITCH.java @@ -0,0 +1,107 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.io.DataOutputStream; +import java.io.IOException; +import org.apache.bcel.util.ByteSequence; + +/** + * TABLESWITCH - Switch within given range of values, i.e., low..high + * + * @version $Id: TABLESWITCH.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see SWITCH + */ +public class TABLESWITCH extends Select { + + /** + * Empty constructor needed for the Class.newInstance() statement in + * Instruction.readInstruction(). Not to be used otherwise. + */ + TABLESWITCH() { + } + + + /** + * @param match sorted array of match values, match[0] must be low value, + * match[match_length - 1] high value + * @param targets where to branch for matched values + * @param defaultTarget default branch + */ + public TABLESWITCH(int[] match, InstructionHandle[] targets, InstructionHandle defaultTarget) { + super(org.apache.bcel.Constants.TABLESWITCH, match, targets, defaultTarget); + length = (short) (13 + match_length * 4); /* Alignment remainder assumed + * 0 here, until dump time */ + fixed_length = length; + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + public void dump( DataOutputStream out ) throws IOException { + super.dump(out); + int low = (match_length > 0) ? match[0] : 0; + out.writeInt(low); + int high = (match_length > 0) ? match[match_length - 1] : 0; + out.writeInt(high); + for (int i = 0; i < match_length; i++) { + out.writeInt(indices[i] = getTargetOffset(targets[i])); + } + } + + + /** + * Read needed data (e.g. index) from file. + */ + protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException { + super.initFromFile(bytes, wide); + int low = bytes.readInt(); + int high = bytes.readInt(); + match_length = high - low + 1; + fixed_length = (short) (13 + match_length * 4); + length = (short) (fixed_length + padding); + match = new int[match_length]; + indices = new int[match_length]; + targets = new InstructionHandle[match_length]; + for (int i = low; i <= high; i++) { + match[i - low] = i; + } + for (int i = 0; i < match_length; i++) { + indices[i] = bytes.readInt(); + } + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + public void accept( Visitor v ) { + v.visitVariableLengthInstruction(this); + v.visitStackProducer(this); + v.visitBranchInstruction(this); + v.visitSelect(this); + v.visitTABLESWITCH(this); + } +} diff --git a/src/org/apache/bcel/generic/TargetLostException.java b/src/org/apache/bcel/generic/TargetLostException.java new file mode 100644 index 0000000..051d0ee --- /dev/null +++ b/src/org/apache/bcel/generic/TargetLostException.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Thrown by InstructionList.remove() when one or multiple disposed instruction + * are still being referenced by a InstructionTargeter object. I.e. the + * InstructionTargeter has to be notified that (one of) the InstructionHandle it + * is referencing is being removed from the InstructionList and thus not valid anymore. + * + * Making this an exception instead of a return value forces the user to handle + * these case explicitely in a try { ... } catch. The following code illustrates + * how this may be done: + * + *

      + *     ...
      + *     try {
      + *	il.delete(start_ih, end_ih);
      + *     } catch(TargetLostException e) {
      + *       InstructionHandle[] targets = e.getTargets();
      + *	 for(int i=0; i < targets.length; i++) {
      + *	   InstructionTargeter[] targeters = targets[i].getTargeters();
      + *     
      + *	   for(int j=0; j < targeters.length; j++)
      + *	     targeters[j].updateTarget(targets[i], new_target);
      + *       }
      + *     }
      + * 
      + * + * @see InstructionHandle + * @see InstructionList + * @see InstructionTargeter + * @version $Id: TargetLostException.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class TargetLostException extends Exception { + + private InstructionHandle[] targets; + + + TargetLostException(InstructionHandle[] t, String mesg) { + super(mesg); + targets = t; + } + + + /** + * @return list of instructions still being targeted. + */ + public InstructionHandle[] getTargets() { + return targets; + } +} diff --git a/src/org/apache/bcel/generic/Type.java b/src/org/apache/bcel/generic/Type.java new file mode 100644 index 0000000..91b2b98 --- /dev/null +++ b/src/org/apache/bcel/generic/Type.java @@ -0,0 +1,310 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +import java.util.ArrayList; +import java.util.List; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.ClassFormatException; +import org.apache.bcel.classfile.Utility; + +/** + * Abstract super class for all possible java types, namely basic types + * such as int, object types like String and array types, e.g. int[] + * + * @version $Id: Type.java 393344 2006-04-12 00:38:34Z tcurdt $ + * @author M. Dahm + */ +public abstract class Type implements java.io.Serializable { + + protected byte type; + protected String signature; // signature for the type + /** Predefined constants + */ + public static final BasicType VOID = new BasicType(Constants.T_VOID); + public static final BasicType BOOLEAN = new BasicType(Constants.T_BOOLEAN); + public static final BasicType INT = new BasicType(Constants.T_INT); + public static final BasicType SHORT = new BasicType(Constants.T_SHORT); + public static final BasicType BYTE = new BasicType(Constants.T_BYTE); + public static final BasicType LONG = new BasicType(Constants.T_LONG); + public static final BasicType DOUBLE = new BasicType(Constants.T_DOUBLE); + public static final BasicType FLOAT = new BasicType(Constants.T_FLOAT); + public static final BasicType CHAR = new BasicType(Constants.T_CHAR); + public static final ObjectType OBJECT = new ObjectType("java.lang.Object"); + public static final ObjectType CLASS = new ObjectType("java.lang.Class"); + public static final ObjectType STRING = new ObjectType("java.lang.String"); + public static final ObjectType STRINGBUFFER = new ObjectType("java.lang.StringBuffer"); + public static final ObjectType THROWABLE = new ObjectType("java.lang.Throwable"); + public static final Type[] NO_ARGS = new Type[0]; + public static final ReferenceType NULL = new ReferenceType() { + }; + public static final Type UNKNOWN = new Type(Constants.T_UNKNOWN, "") { + }; + + + protected Type(byte t, String s) { + type = t; + signature = s; + } + + + /** + * @return hashcode of Type + */ + public int hashCode() { + return type ^ signature.hashCode(); + } + + + /** + * @return whether the Types are equal + */ + public boolean equals(Object o) { + if (o instanceof Type) { + Type t = (Type)o; + return (type == t.type) && signature.equals(t.signature); + } + return false; + } + + + /** + * @return signature for given type. + */ + public String getSignature() { + return signature; + } + + + /** + * @return type as defined in Constants + */ + public byte getType() { + return type; + } + + + /** + * @return stack size of this type (2 for long and double, 0 for void, 1 otherwise) + */ + public int getSize() { + switch (type) { + case Constants.T_DOUBLE: + case Constants.T_LONG: + return 2; + case Constants.T_VOID: + return 0; + default: + return 1; + } + } + + + /** + * @return Type string, e.g. `int[]' + */ + public String toString() { + return ((this.equals(Type.NULL) || (type >= Constants.T_UNKNOWN))) ? signature : Utility + .signatureToString(signature, false); + } + + + /** + * Convert type to Java method signature, e.g. int[] f(java.lang.String x) + * becomes (Ljava/lang/String;)[I + * + * @param return_type what the method returns + * @param arg_types what are the argument types + * @return method signature for given type(s). + */ + public static String getMethodSignature( Type return_type, Type[] arg_types ) { + StringBuffer buf = new StringBuffer("("); + int length = (arg_types == null) ? 0 : arg_types.length; + for (int i = 0; i < length; i++) { + buf.append(arg_types[i].getSignature()); + } + buf.append(')'); + buf.append(return_type.getSignature()); + return buf.toString(); + } + + private static ThreadLocal consumed_chars = new ThreadLocal() { + + protected Object initialValue() { + return new Integer(0); + } + };//int consumed_chars=0; // Remember position in string, see getArgumentTypes + + + private static int unwrap( ThreadLocal tl ) { + return ((Integer) tl.get()).intValue(); + } + + + private static void wrap( ThreadLocal tl, int value ) { + tl.set(new Integer(value)); + } + + + /** + * Convert signature to a Type object. + * @param signature signature string such as Ljava/lang/String; + * @return type object + */ + public static final Type getType( String signature ) throws StringIndexOutOfBoundsException { + byte type = Utility.typeOfSignature(signature); + if (type <= Constants.T_VOID) { + //corrected concurrent private static field acess + wrap(consumed_chars, 1); + return BasicType.getType(type); + } else if (type == Constants.T_ARRAY) { + int dim = 0; + do { // Count dimensions + dim++; + } while (signature.charAt(dim) == '['); + // Recurse, but just once, if the signature is ok + Type t = getType(signature.substring(dim)); + //corrected concurrent private static field acess + // consumed_chars += dim; // update counter - is replaced by + int _temp = unwrap(consumed_chars) + dim; + wrap(consumed_chars, _temp); + return new ArrayType(t, dim); + } else { // type == T_REFERENCE + int index = signature.indexOf(';'); // Look for closing `;' + if (index < 0) { + throw new ClassFormatException("Invalid signature: " + signature); + } + //corrected concurrent private static field acess + wrap(consumed_chars, index + 1); // "Lblabla;" `L' and `;' are removed + return new ObjectType(signature.substring(1, index).replace('/', '.')); + } + } + + + /** + * Convert return value of a method (signature) to a Type object. + * + * @param signature signature string such as (Ljava/lang/String;)V + * @return return type + */ + public static Type getReturnType( String signature ) { + try { + // Read return type after `)' + int index = signature.lastIndexOf(')') + 1; + return getType(signature.substring(index)); + } catch (StringIndexOutOfBoundsException e) { // Should never occur + throw new ClassFormatException("Invalid method signature: " + signature); + } + } + + + /** + * Convert arguments of a method (signature) to an array of Type objects. + * @param signature signature string such as (Ljava/lang/String;)V + * @return array of argument types + */ + public static Type[] getArgumentTypes( String signature ) { + List vec = new ArrayList(); + int index; + Type[] types; + try { // Read all declarations between for `(' and `)' + if (signature.charAt(0) != '(') { + throw new ClassFormatException("Invalid method signature: " + signature); + } + index = 1; // current string position + while (signature.charAt(index) != ')') { + vec.add(getType(signature.substring(index))); + //corrected concurrent private static field acess + index += unwrap(consumed_chars); // update position + } + } catch (StringIndexOutOfBoundsException e) { // Should never occur + throw new ClassFormatException("Invalid method signature: " + signature); + } + types = new Type[vec.size()]; + vec.toArray(types); + return types; + } + + + /** Convert runtime java.lang.Class to BCEL Type object. + * @param cl Java class + * @return corresponding Type object + */ + public static Type getType( java.lang.Class cl ) { + if (cl == null) { + throw new IllegalArgumentException("Class must not be null"); + } + /* That's an amzingly easy case, because getName() returns + * the signature. That's what we would have liked anyway. + */ + if (cl.isArray()) { + return getType(cl.getName()); + } else if (cl.isPrimitive()) { + if (cl == Integer.TYPE) { + return INT; + } else if (cl == Void.TYPE) { + return VOID; + } else if (cl == Double.TYPE) { + return DOUBLE; + } else if (cl == Float.TYPE) { + return FLOAT; + } else if (cl == Boolean.TYPE) { + return BOOLEAN; + } else if (cl == Byte.TYPE) { + return BYTE; + } else if (cl == Short.TYPE) { + return SHORT; + } else if (cl == Byte.TYPE) { + return BYTE; + } else if (cl == Long.TYPE) { + return LONG; + } else if (cl == Character.TYPE) { + return CHAR; + } else { + throw new IllegalStateException("Ooops, what primitive type is " + cl); + } + } else { // "Real" class + return new ObjectType(cl.getName()); + } + } + + + /** + * Convert runtime java.lang.Class[] to BCEL Type objects. + * @param classes an array of runtime class objects + * @return array of corresponding Type objects + */ + public static Type[] getTypes( java.lang.Class[] classes ) { + Type[] ret = new Type[classes.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = getType(classes[i]); + } + return ret; + } + + + public static String getSignature( java.lang.reflect.Method meth ) { + StringBuffer sb = new StringBuffer("("); + Class[] params = meth.getParameterTypes(); // avoid clone + for (int j = 0; j < params.length; j++) { + sb.append(getType(params[j]).getSignature()); + } + sb.append(")"); + sb.append(getType(meth.getReturnType()).getSignature()); + return sb.toString(); + } +} diff --git a/src/org/apache/bcel/generic/TypedInstruction.java b/src/org/apache/bcel/generic/TypedInstruction.java new file mode 100644 index 0000000..dc9899f --- /dev/null +++ b/src/org/apache/bcel/generic/TypedInstruction.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Get the type associated with an instruction, int for ILOAD, or the type + * of the field of a PUTFIELD instruction, e.g.. + * + * @version $Id: TypedInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface TypedInstruction { + + public Type getType( ConstantPoolGen cpg ); +} diff --git a/src/org/apache/bcel/generic/UnconditionalBranch.java b/src/org/apache/bcel/generic/UnconditionalBranch.java new file mode 100644 index 0000000..1bdfba4 --- /dev/null +++ b/src/org/apache/bcel/generic/UnconditionalBranch.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denotes an instruction to perform an unconditional branch, i.e., GOTO, JSR. + * + * @version $Id: UnconditionalBranch.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + + * @see GOTO + * @see JSR + */ +public interface UnconditionalBranch { +} diff --git a/src/org/apache/bcel/generic/VariableLengthInstruction.java b/src/org/apache/bcel/generic/VariableLengthInstruction.java new file mode 100644 index 0000000..bc9402e --- /dev/null +++ b/src/org/apache/bcel/generic/VariableLengthInstruction.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Denotes an instruction to be a variable length instruction, such as + * GOTO, JSR, LOOKUPSWITCH and TABLESWITCH. + * + * @version $Id: VariableLengthInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + + * @see GOTO + * @see JSR + * @see LOOKUPSWITCH + * @see TABLESWITCH + */ +public interface VariableLengthInstruction { +} diff --git a/src/org/apache/bcel/generic/Visitor.java b/src/org/apache/bcel/generic/Visitor.java new file mode 100644 index 0000000..6178f66 --- /dev/null +++ b/src/org/apache/bcel/generic/Visitor.java @@ -0,0 +1,568 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.generic; + +/** + * Interface implementing the Visitor pattern programming style. + * I.e., a class that implements this interface can handle all types of + * instructions with the properly typed methods just by calling the accept() + * method. + * + * @version $Id: Visitor.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public interface Visitor { + + public void visitStackInstruction( StackInstruction obj ); + + + public void visitLocalVariableInstruction( LocalVariableInstruction obj ); + + + public void visitBranchInstruction( BranchInstruction obj ); + + + public void visitLoadClass( LoadClass obj ); + + + public void visitFieldInstruction( FieldInstruction obj ); + + + public void visitIfInstruction( IfInstruction obj ); + + + public void visitConversionInstruction( ConversionInstruction obj ); + + + public void visitPopInstruction( PopInstruction obj ); + + + public void visitStoreInstruction( StoreInstruction obj ); + + + public void visitTypedInstruction( TypedInstruction obj ); + + + public void visitSelect( Select obj ); + + + public void visitJsrInstruction( JsrInstruction obj ); + + + public void visitGotoInstruction( GotoInstruction obj ); + + + public void visitUnconditionalBranch( UnconditionalBranch obj ); + + + public void visitPushInstruction( PushInstruction obj ); + + + public void visitArithmeticInstruction( ArithmeticInstruction obj ); + + + public void visitCPInstruction( CPInstruction obj ); + + + public void visitInvokeInstruction( InvokeInstruction obj ); + + + public void visitArrayInstruction( ArrayInstruction obj ); + + + public void visitAllocationInstruction( AllocationInstruction obj ); + + + public void visitReturnInstruction( ReturnInstruction obj ); + + + public void visitFieldOrMethod( FieldOrMethod obj ); + + + public void visitConstantPushInstruction( ConstantPushInstruction obj ); + + + public void visitExceptionThrower( ExceptionThrower obj ); + + + public void visitLoadInstruction( LoadInstruction obj ); + + + public void visitVariableLengthInstruction( VariableLengthInstruction obj ); + + + public void visitStackProducer( StackProducer obj ); + + + public void visitStackConsumer( StackConsumer obj ); + + + public void visitACONST_NULL( ACONST_NULL obj ); + + + public void visitGETSTATIC( GETSTATIC obj ); + + + public void visitIF_ICMPLT( IF_ICMPLT obj ); + + + public void visitMONITOREXIT( MONITOREXIT obj ); + + + public void visitIFLT( IFLT obj ); + + + public void visitLSTORE( LSTORE obj ); + + + public void visitPOP2( POP2 obj ); + + + public void visitBASTORE( BASTORE obj ); + + + public void visitISTORE( ISTORE obj ); + + + public void visitCHECKCAST( CHECKCAST obj ); + + + public void visitFCMPG( FCMPG obj ); + + + public void visitI2F( I2F obj ); + + + public void visitATHROW( ATHROW obj ); + + + public void visitDCMPL( DCMPL obj ); + + + public void visitARRAYLENGTH( ARRAYLENGTH obj ); + + + public void visitDUP( DUP obj ); + + + public void visitINVOKESTATIC( INVOKESTATIC obj ); + + + public void visitLCONST( LCONST obj ); + + + public void visitDREM( DREM obj ); + + + public void visitIFGE( IFGE obj ); + + + public void visitCALOAD( CALOAD obj ); + + + public void visitLASTORE( LASTORE obj ); + + + public void visitI2D( I2D obj ); + + + public void visitDADD( DADD obj ); + + + public void visitINVOKESPECIAL( INVOKESPECIAL obj ); + + + public void visitIAND( IAND obj ); + + + public void visitPUTFIELD( PUTFIELD obj ); + + + public void visitILOAD( ILOAD obj ); + + + public void visitDLOAD( DLOAD obj ); + + + public void visitDCONST( DCONST obj ); + + + public void visitNEW( NEW obj ); + + + public void visitIFNULL( IFNULL obj ); + + + public void visitLSUB( LSUB obj ); + + + public void visitL2I( L2I obj ); + + + public void visitISHR( ISHR obj ); + + + public void visitTABLESWITCH( TABLESWITCH obj ); + + + public void visitIINC( IINC obj ); + + + public void visitDRETURN( DRETURN obj ); + + + public void visitFSTORE( FSTORE obj ); + + + public void visitDASTORE( DASTORE obj ); + + + public void visitIALOAD( IALOAD obj ); + + + public void visitDDIV( DDIV obj ); + + + public void visitIF_ICMPGE( IF_ICMPGE obj ); + + + public void visitLAND( LAND obj ); + + + public void visitIDIV( IDIV obj ); + + + public void visitLOR( LOR obj ); + + + public void visitCASTORE( CASTORE obj ); + + + public void visitFREM( FREM obj ); + + + public void visitLDC( LDC obj ); + + + public void visitBIPUSH( BIPUSH obj ); + + + public void visitDSTORE( DSTORE obj ); + + + public void visitF2L( F2L obj ); + + + public void visitFMUL( FMUL obj ); + + + public void visitLLOAD( LLOAD obj ); + + + public void visitJSR( JSR obj ); + + + public void visitFSUB( FSUB obj ); + + + public void visitSASTORE( SASTORE obj ); + + + public void visitALOAD( ALOAD obj ); + + + public void visitDUP2_X2( DUP2_X2 obj ); + + + public void visitRETURN( RETURN obj ); + + + public void visitDALOAD( DALOAD obj ); + + + public void visitSIPUSH( SIPUSH obj ); + + + public void visitDSUB( DSUB obj ); + + + public void visitL2F( L2F obj ); + + + public void visitIF_ICMPGT( IF_ICMPGT obj ); + + + public void visitF2D( F2D obj ); + + + public void visitI2L( I2L obj ); + + + public void visitIF_ACMPNE( IF_ACMPNE obj ); + + + public void visitPOP( POP obj ); + + + public void visitI2S( I2S obj ); + + + public void visitIFEQ( IFEQ obj ); + + + public void visitSWAP( SWAP obj ); + + + public void visitIOR( IOR obj ); + + + public void visitIREM( IREM obj ); + + + public void visitIASTORE( IASTORE obj ); + + + public void visitNEWARRAY( NEWARRAY obj ); + + + public void visitINVOKEINTERFACE( INVOKEINTERFACE obj ); + + + public void visitINEG( INEG obj ); + + + public void visitLCMP( LCMP obj ); + + + public void visitJSR_W( JSR_W obj ); + + + public void visitMULTIANEWARRAY( MULTIANEWARRAY obj ); + + + public void visitDUP_X2( DUP_X2 obj ); + + + public void visitSALOAD( SALOAD obj ); + + + public void visitIFNONNULL( IFNONNULL obj ); + + + public void visitDMUL( DMUL obj ); + + + public void visitIFNE( IFNE obj ); + + + public void visitIF_ICMPLE( IF_ICMPLE obj ); + + + public void visitLDC2_W( LDC2_W obj ); + + + public void visitGETFIELD( GETFIELD obj ); + + + public void visitLADD( LADD obj ); + + + public void visitNOP( NOP obj ); + + + public void visitFALOAD( FALOAD obj ); + + + public void visitINSTANCEOF( INSTANCEOF obj ); + + + public void visitIFLE( IFLE obj ); + + + public void visitLXOR( LXOR obj ); + + + public void visitLRETURN( LRETURN obj ); + + + public void visitFCONST( FCONST obj ); + + + public void visitIUSHR( IUSHR obj ); + + + public void visitBALOAD( BALOAD obj ); + + + public void visitDUP2( DUP2 obj ); + + + public void visitIF_ACMPEQ( IF_ACMPEQ obj ); + + + public void visitIMPDEP1( IMPDEP1 obj ); + + + public void visitMONITORENTER( MONITORENTER obj ); + + + public void visitLSHL( LSHL obj ); + + + public void visitDCMPG( DCMPG obj ); + + + public void visitD2L( D2L obj ); + + + public void visitIMPDEP2( IMPDEP2 obj ); + + + public void visitL2D( L2D obj ); + + + public void visitRET( RET obj ); + + + public void visitIFGT( IFGT obj ); + + + public void visitIXOR( IXOR obj ); + + + public void visitINVOKEVIRTUAL( INVOKEVIRTUAL obj ); + + + public void visitFASTORE( FASTORE obj ); + + + public void visitIRETURN( IRETURN obj ); + + + public void visitIF_ICMPNE( IF_ICMPNE obj ); + + + public void visitFLOAD( FLOAD obj ); + + + public void visitLDIV( LDIV obj ); + + + public void visitPUTSTATIC( PUTSTATIC obj ); + + + public void visitAALOAD( AALOAD obj ); + + + public void visitD2I( D2I obj ); + + + public void visitIF_ICMPEQ( IF_ICMPEQ obj ); + + + public void visitAASTORE( AASTORE obj ); + + + public void visitARETURN( ARETURN obj ); + + + public void visitDUP2_X1( DUP2_X1 obj ); + + + public void visitFNEG( FNEG obj ); + + + public void visitGOTO_W( GOTO_W obj ); + + + public void visitD2F( D2F obj ); + + + public void visitGOTO( GOTO obj ); + + + public void visitISUB( ISUB obj ); + + + public void visitF2I( F2I obj ); + + + public void visitDNEG( DNEG obj ); + + + public void visitICONST( ICONST obj ); + + + public void visitFDIV( FDIV obj ); + + + public void visitI2B( I2B obj ); + + + public void visitLNEG( LNEG obj ); + + + public void visitLREM( LREM obj ); + + + public void visitIMUL( IMUL obj ); + + + public void visitIADD( IADD obj ); + + + public void visitLSHR( LSHR obj ); + + + public void visitLOOKUPSWITCH( LOOKUPSWITCH obj ); + + + public void visitDUP_X1( DUP_X1 obj ); + + + public void visitFCMPL( FCMPL obj ); + + + public void visitI2C( I2C obj ); + + + public void visitLMUL( LMUL obj ); + + + public void visitLUSHR( LUSHR obj ); + + + public void visitISHL( ISHL obj ); + + + public void visitLALOAD( LALOAD obj ); + + + public void visitASTORE( ASTORE obj ); + + + public void visitANEWARRAY( ANEWARRAY obj ); + + + public void visitFRETURN( FRETURN obj ); + + + public void visitFADD( FADD obj ); + + + public void visitBREAKPOINT( BREAKPOINT obj ); +} diff --git a/src/org/apache/bcel/generic/package.html b/src/org/apache/bcel/generic/package.html new file mode 100644 index 0000000..201d573 --- /dev/null +++ b/src/org/apache/bcel/generic/package.html @@ -0,0 +1,16 @@ + + + + + + +

      +This package contains the "generic" part of the +Byte Code Engineering +Library, i.e., classes to dynamically modify class objects and +byte code instructions. +

      + + diff --git a/src/org/apache/bcel/package.html b/src/org/apache/bcel/package.html new file mode 100644 index 0000000..aaded50 --- /dev/null +++ b/src/org/apache/bcel/package.html @@ -0,0 +1,17 @@ + + + + + + +

      +This package contains basic classes for the +Byte Code Engineering Library + and constants defined by the + + JVM specification. +

      + + diff --git a/src/org/apache/bcel/util/AttributeHTML.java b/src/org/apache/bcel/util/AttributeHTML.java new file mode 100644 index 0000000..6b0441d --- /dev/null +++ b/src/org/apache/bcel/util/AttributeHTML.java @@ -0,0 +1,211 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import org.apache.bcel.classfile.Attribute; +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.CodeException; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.ConstantUtf8; +import org.apache.bcel.classfile.ConstantValue; +import org.apache.bcel.classfile.ExceptionTable; +import org.apache.bcel.classfile.InnerClass; +import org.apache.bcel.classfile.InnerClasses; +import org.apache.bcel.classfile.LineNumber; +import org.apache.bcel.classfile.LineNumberTable; +import org.apache.bcel.classfile.LocalVariable; +import org.apache.bcel.classfile.LocalVariableTable; +import org.apache.bcel.classfile.SourceFile; +import org.apache.bcel.classfile.Utility; + +/** + * Convert found attributes into HTML file. + * + * @version $Id: AttributeHTML.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * + */ +final class AttributeHTML implements org.apache.bcel.Constants { + + private String class_name; // name of current class + private PrintWriter file; // file to write to + private int attr_count = 0; + private ConstantHTML constant_html; + private ConstantPool constant_pool; + + + AttributeHTML(String dir, String class_name, ConstantPool constant_pool, + ConstantHTML constant_html) throws IOException { + this.class_name = class_name; + this.constant_pool = constant_pool; + this.constant_html = constant_html; + file = new PrintWriter(new FileOutputStream(dir + class_name + "_attributes.html")); + file.println(""); + } + + + private final String codeLink( int link, int method_number ) { + return "" + link + ""; + } + + + final void close() { + file.println("
      "); + file.close(); + } + + + final void writeAttribute( Attribute attribute, String anchor ) throws IOException { + writeAttribute(attribute, anchor, 0); + } + + + final void writeAttribute( Attribute attribute, String anchor, int method_number ) + throws IOException { + byte tag = attribute.getTag(); + int index; + if (tag == ATTR_UNKNOWN) { + return; + } + attr_count++; // Increment number of attributes found so far + if (attr_count % 2 == 0) { + file.print(""); + } else { + file.print(""); + } + file.println("

      " + attr_count + " " + ATTRIBUTE_NAMES[tag] + + "

      "); + /* Handle different attributes + */ + switch (tag) { + case ATTR_CODE: + Code c = (Code) attribute; + // Some directly printable values + file.print("
      • Maximum stack size = " + c.getMaxStack() + + "
      • \n
      • Number of local variables = " + c.getMaxLocals() + + "
      • \n
      • Byte code
      \n"); + // Get handled exceptions and list them + CodeException[] ce = c.getExceptionTable(); + int len = ce.length; + if (len > 0) { + file.print("

      Exceptions handled

        "); + for (int i = 0; i < len; i++) { + int catch_type = ce[i].getCatchType(); // Index in constant pool + file.print("
      • "); + if (catch_type != 0) { + file.print(constant_html.referenceConstant(catch_type)); // Create Link to _cp.html + } else { + file.print("Any Exception"); + } + file.print("
        (Ranging from lines " + + codeLink(ce[i].getStartPC(), method_number) + " to " + + codeLink(ce[i].getEndPC(), method_number) + ", handled at line " + + codeLink(ce[i].getHandlerPC(), method_number) + ")
      • "); + } + file.print("
      "); + } + break; + case ATTR_CONSTANT_VALUE: + index = ((ConstantValue) attribute).getConstantValueIndex(); + // Reference _cp.html + file.print("\n"); + break; + case ATTR_SOURCE_FILE: + index = ((SourceFile) attribute).getSourceFileIndex(); + // Reference _cp.html + file.print("\n"); + break; + case ATTR_EXCEPTIONS: + // List thrown exceptions + int[] indices = ((ExceptionTable) attribute).getExceptionIndexTable(); + file.print("\n"); + break; + case ATTR_LINE_NUMBER_TABLE: + LineNumber[] line_numbers = ((LineNumberTable) attribute).getLineNumberTable(); + // List line number pairs + file.print("

      "); + for (int i = 0; i < line_numbers.length; i++) { + file.print("(" + line_numbers[i].getStartPC() + ", " + + line_numbers[i].getLineNumber() + ")"); + if (i < line_numbers.length - 1) { + file.print(", "); // breakable + } + } + break; + case ATTR_LOCAL_VARIABLE_TABLE: + LocalVariable[] vars = ((LocalVariableTable) attribute).getLocalVariableTable(); + // List name, range and type + file.print("

        "); + for (int i = 0; i < vars.length; i++) { + index = vars[i].getSignatureIndex(); + String signature = ((ConstantUtf8) constant_pool.getConstant(index, + CONSTANT_Utf8)).getBytes(); + signature = Utility.signatureToString(signature, false); + int start = vars[i].getStartPC(); + int end = (start + vars[i].getLength()); + file.println("
      • " + Class2HTML.referenceType(signature) + " " + + vars[i].getName() + " in slot %" + vars[i].getIndex() + + "
        Valid from lines " + "" + + start + " to " + "" + end + "
      • "); + } + file.print("
      \n"); + break; + case ATTR_INNER_CLASSES: + InnerClass[] classes = ((InnerClasses) attribute).getInnerClasses(); + // List inner classes + file.print("
        "); + for (int i = 0; i < classes.length; i++) { + String name, access; + index = classes[i].getInnerNameIndex(); + if (index > 0) { + name = ((ConstantUtf8) constant_pool.getConstant(index, CONSTANT_Utf8)) + .getBytes(); + } else { + name = "<anonymous>"; + } + access = Utility.accessToString(classes[i].getInnerAccessFlags()); + file.print("
      • " + access + " " + + constant_html.referenceConstant(classes[i].getInnerClassIndex()) + + " in class " + + constant_html.referenceConstant(classes[i].getOuterClassIndex()) + + " named " + name + "
      • \n"); + } + file.print("
      \n"); + break; + default: // Such as Unknown attribute or Deprecated + file.print("

      " + attribute.toString()); + } + file.println(""); + file.flush(); + } +} diff --git a/src/org/apache/bcel/util/BCELComparator.java b/src/org/apache/bcel/util/BCELComparator.java new file mode 100644 index 0000000..9404bd3 --- /dev/null +++ b/src/org/apache/bcel/util/BCELComparator.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +/** + * Used for BCEL comparison strategy + * + * @author M. Dahm + * @version $Id: BCELComparator.java 410087 2006-05-29 12:12:19Z tcurdt $ + * @since 5.2 + */ +public interface BCELComparator { + + /** + * Compare two objects and return what THIS.equals(THAT) should return + * + * @param THIS + * @param THAT + * @return true if and only if THIS equals THAT + */ + public boolean equals( Object THIS, Object THAT ); + + + /** + * Return hashcode for THIS.hashCode() + * + * @param THIS + * @return hashcode for THIS.hashCode() + */ + public int hashCode( Object THIS ); +} diff --git a/src/org/apache/bcel/util/BCELFactory.java b/src/org/apache/bcel/util/BCELFactory.java new file mode 100644 index 0000000..2704a57 --- /dev/null +++ b/src/org/apache/bcel/util/BCELFactory.java @@ -0,0 +1,326 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.Utility; +import org.apache.bcel.generic.AllocationInstruction; +import org.apache.bcel.generic.ArrayInstruction; +import org.apache.bcel.generic.ArrayType; +import org.apache.bcel.generic.BranchHandle; +import org.apache.bcel.generic.BranchInstruction; +import org.apache.bcel.generic.CHECKCAST; +import org.apache.bcel.generic.CPInstruction; +import org.apache.bcel.generic.CodeExceptionGen; +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.ConstantPushInstruction; +import org.apache.bcel.generic.EmptyVisitor; +import org.apache.bcel.generic.FieldInstruction; +import org.apache.bcel.generic.IINC; +import org.apache.bcel.generic.INSTANCEOF; +import org.apache.bcel.generic.Instruction; +import org.apache.bcel.generic.InstructionConstants; +import org.apache.bcel.generic.InstructionHandle; +import org.apache.bcel.generic.InvokeInstruction; +import org.apache.bcel.generic.LDC; +import org.apache.bcel.generic.LDC2_W; +import org.apache.bcel.generic.LocalVariableInstruction; +import org.apache.bcel.generic.MULTIANEWARRAY; +import org.apache.bcel.generic.MethodGen; +import org.apache.bcel.generic.NEWARRAY; +import org.apache.bcel.generic.ObjectType; +import org.apache.bcel.generic.RET; +import org.apache.bcel.generic.ReturnInstruction; +import org.apache.bcel.generic.Select; +import org.apache.bcel.generic.Type; + +/** + * Factory creates il.append() statements, and sets instruction targets. + * A helper class for BCELifier. + * + * @see BCELifier + * @version $Id: BCELFactory.java 410087 2006-05-29 12:12:19Z tcurdt $ + * @author M. Dahm + */ +class BCELFactory extends EmptyVisitor { + + private MethodGen _mg; + private PrintWriter _out; + private ConstantPoolGen _cp; + + + BCELFactory(MethodGen mg, PrintWriter out) { + _mg = mg; + _cp = mg.getConstantPool(); + _out = out; + } + + private Map branch_map = new HashMap(); // Map + + + public void start() { + if (!_mg.isAbstract() && !_mg.isNative()) { + for (InstructionHandle ih = _mg.getInstructionList().getStart(); ih != null; ih = ih + .getNext()) { + Instruction i = ih.getInstruction(); + if (i instanceof BranchInstruction) { + branch_map.put(i, ih); // memorize container + } + if (ih.hasTargeters()) { + if (i instanceof BranchInstruction) { + _out.println(" InstructionHandle ih_" + ih.getPosition() + ";"); + } else { + _out.print(" InstructionHandle ih_" + ih.getPosition() + " = "); + } + } else { + _out.print(" "); + } + if (!visitInstruction(i)) { + i.accept(this); + } + } + updateBranchTargets(); + updateExceptionHandlers(); + } + } + + + private boolean visitInstruction( Instruction i ) { + short opcode = i.getOpcode(); + if ((InstructionConstants.INSTRUCTIONS[opcode] != null) + && !(i instanceof ConstantPushInstruction) && !(i instanceof ReturnInstruction)) { // Handled below + _out.println("il.append(InstructionConstants." + + i.getName().toUpperCase(Locale.ENGLISH) + ");"); + return true; + } + return false; + } + + + public void visitLocalVariableInstruction( LocalVariableInstruction i ) { + short opcode = i.getOpcode(); + Type type = i.getType(_cp); + if (opcode == Constants.IINC) { + _out.println("il.append(new IINC(" + i.getIndex() + ", " + ((IINC) i).getIncrement() + + "));"); + } else { + String kind = (opcode < Constants.ISTORE) ? "Load" : "Store"; + _out.println("il.append(_factory.create" + kind + "(" + BCELifier.printType(type) + + ", " + i.getIndex() + "));"); + } + } + + + public void visitArrayInstruction( ArrayInstruction i ) { + short opcode = i.getOpcode(); + Type type = i.getType(_cp); + String kind = (opcode < Constants.IASTORE) ? "Load" : "Store"; + _out.println("il.append(_factory.createArray" + kind + "(" + BCELifier.printType(type) + + "));"); + } + + + public void visitFieldInstruction( FieldInstruction i ) { + short opcode = i.getOpcode(); + String class_name = i.getClassName(_cp); + String field_name = i.getFieldName(_cp); + Type type = i.getFieldType(_cp); + _out.println("il.append(_factory.createFieldAccess(\"" + class_name + "\", \"" + field_name + + "\", " + BCELifier.printType(type) + ", " + "Constants." + + Constants.OPCODE_NAMES[opcode].toUpperCase(Locale.ENGLISH) + "));"); + } + + + public void visitInvokeInstruction( InvokeInstruction i ) { + short opcode = i.getOpcode(); + String class_name = i.getClassName(_cp); + String method_name = i.getMethodName(_cp); + Type type = i.getReturnType(_cp); + Type[] arg_types = i.getArgumentTypes(_cp); + _out.println("il.append(_factory.createInvoke(\"" + class_name + "\", \"" + method_name + + "\", " + BCELifier.printType(type) + ", " + + BCELifier.printArgumentTypes(arg_types) + ", " + "Constants." + + Constants.OPCODE_NAMES[opcode].toUpperCase(Locale.ENGLISH) + "));"); + } + + + public void visitAllocationInstruction( AllocationInstruction i ) { + Type type; + if (i instanceof CPInstruction) { + type = ((CPInstruction) i).getType(_cp); + } else { + type = ((NEWARRAY) i).getType(); + } + short opcode = ((Instruction) i).getOpcode(); + int dim = 1; + switch (opcode) { + case Constants.NEW: + _out.println("il.append(_factory.createNew(\"" + ((ObjectType) type).getClassName() + + "\"));"); + break; + case Constants.MULTIANEWARRAY: + dim = ((MULTIANEWARRAY) i).getDimensions(); + case Constants.ANEWARRAY: + case Constants.NEWARRAY: + if (type instanceof ArrayType) { + type = ((ArrayType) type).getBasicType(); + } + _out.println("il.append(_factory.createNewArray(" + BCELifier.printType(type) + + ", (short) " + dim + "));"); + break; + default: + throw new RuntimeException("Oops: " + opcode); + } + } + + + private void createConstant( Object value ) { + String embed = value.toString(); + if (value instanceof String) { + embed = '"' + Utility.convertString(value.toString()) + '"'; + } else if (value instanceof Character) { + embed = "(char)0x" + Integer.toHexString(((Character) value).charValue()); + } + _out.println("il.append(new PUSH(_cp, " + embed + "));"); + } + + + public void visitLDC( LDC i ) { + createConstant(i.getValue(_cp)); + } + + + public void visitLDC2_W( LDC2_W i ) { + createConstant(i.getValue(_cp)); + } + + + public void visitConstantPushInstruction( ConstantPushInstruction i ) { + createConstant(i.getValue()); + } + + + public void visitINSTANCEOF( INSTANCEOF i ) { + Type type = i.getType(_cp); + _out.println("il.append(new INSTANCEOF(_cp.addClass(" + BCELifier.printType(type) + ")));"); + } + + + public void visitCHECKCAST( CHECKCAST i ) { + Type type = i.getType(_cp); + _out.println("il.append(_factory.createCheckCast(" + BCELifier.printType(type) + "));"); + } + + + public void visitReturnInstruction( ReturnInstruction i ) { + Type type = i.getType(_cp); + _out.println("il.append(_factory.createReturn(" + BCELifier.printType(type) + "));"); + } + + // Memorize BranchInstructions that need an update + private List branches = new ArrayList(); + + + public void visitBranchInstruction( BranchInstruction bi ) { + BranchHandle bh = (BranchHandle) branch_map.get(bi); + int pos = bh.getPosition(); + String name = bi.getName() + "_" + pos; + if (bi instanceof Select) { + Select s = (Select) bi; + branches.add(bi); + StringBuffer args = new StringBuffer("new int[] { "); + int[] matchs = s.getMatchs(); + for (int i = 0; i < matchs.length; i++) { + args.append(matchs[i]); + if (i < matchs.length - 1) { + args.append(", "); + } + } + args.append(" }"); + _out.print("Select " + name + " = new " + bi.getName().toUpperCase(Locale.ENGLISH) + + "(" + args + ", new InstructionHandle[] { "); + for (int i = 0; i < matchs.length; i++) { + _out.print("null"); + if (i < matchs.length - 1) { + _out.print(", "); + } + } + _out.println(" }, null);"); + } else { + int t_pos = bh.getTarget().getPosition(); + String target; + if (pos > t_pos) { + target = "ih_" + t_pos; + } else { + branches.add(bi); + target = "null"; + } + _out.println(" BranchInstruction " + name + " = _factory.createBranchInstruction(" + + "Constants." + bi.getName().toUpperCase(Locale.ENGLISH) + ", " + target + + ");"); + } + if (bh.hasTargeters()) { + _out.println(" ih_" + pos + " = il.append(" + name + ");"); + } else { + _out.println(" il.append(" + name + ");"); + } + } + + + public void visitRET( RET i ) { + _out.println("il.append(new RET(" + i.getIndex() + ")));"); + } + + + private void updateBranchTargets() { + for (Iterator i = branches.iterator(); i.hasNext();) { + BranchInstruction bi = (BranchInstruction) i.next(); + BranchHandle bh = (BranchHandle) branch_map.get(bi); + int pos = bh.getPosition(); + String name = bi.getName() + "_" + pos; + int t_pos = bh.getTarget().getPosition(); + _out.println(" " + name + ".setTarget(ih_" + t_pos + ");"); + if (bi instanceof Select) { + InstructionHandle[] ihs = ((Select) bi).getTargets(); + for (int j = 0; j < ihs.length; j++) { + t_pos = ihs[j].getPosition(); + _out.println(" " + name + ".setTarget(" + j + ", ih_" + t_pos + ");"); + } + } + } + } + + + private void updateExceptionHandlers() { + CodeExceptionGen[] handlers = _mg.getExceptionHandlers(); + for (int i = 0; i < handlers.length; i++) { + CodeExceptionGen h = handlers[i]; + String type = (h.getCatchType() == null) ? "null" : BCELifier.printType(h + .getCatchType()); + _out.println(" method.addExceptionHandler(" + "ih_" + h.getStartPC().getPosition() + + ", " + "ih_" + h.getEndPC().getPosition() + ", " + "ih_" + + h.getHandlerPC().getPosition() + ", " + type + ");"); + } + } +} diff --git a/src/org/apache/bcel/util/BCELifier.java b/src/org/apache/bcel/util/BCELifier.java new file mode 100644 index 0000000..c4ebbe2 --- /dev/null +++ b/src/org/apache/bcel/util/BCELifier.java @@ -0,0 +1,268 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.Locale; +import org.apache.bcel.Constants; +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.ClassParser; +import org.apache.bcel.classfile.ConstantValue; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.Utility; +import org.apache.bcel.generic.ArrayType; +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.MethodGen; +import org.apache.bcel.generic.Type; + +/** + * This class takes a given JavaClass object and converts it to a + * Java program that creates that very class using BCEL. This + * gives new users of BCEL a useful example showing how things + * are done with BCEL. It does not cover all features of BCEL, + * but tries to mimic hand-written code as close as possible. + * + * @version $Id: BCELifier.java 394939 2006-04-18 13:23:49Z tcurdt $ + * @author M. Dahm + */ +public class BCELifier extends org.apache.bcel.classfile.EmptyVisitor { + + private static final int FLAG_FOR_UNKNOWN = -1; + private static final int FLAG_FOR_CLASS = 0; + private static final int FLAG_FOR_METHOD = 1; + private JavaClass _clazz; + private PrintWriter _out; + private ConstantPoolGen _cp; + + + /** @param clazz Java class to "decompile" + * @param out where to output Java program + */ + public BCELifier(JavaClass clazz, OutputStream out) { + _clazz = clazz; + _out = new PrintWriter(out); + _cp = new ConstantPoolGen(_clazz.getConstantPool()); + } + + + /** Start Java code generation + */ + public void start() { + visitJavaClass(_clazz); + _out.flush(); + } + + + public void visitJavaClass( JavaClass clazz ) { + String class_name = clazz.getClassName(); + String super_name = clazz.getSuperclassName(); + String package_name = clazz.getPackageName(); + String inter = Utility.printArray(clazz.getInterfaceNames(), false, true); + if (!"".equals(package_name)) { + class_name = class_name.substring(package_name.length() + 1); + _out.println("package " + package_name + ";"); + _out.println(); + } + _out.println("import org.apache.bcel.generic.*;"); + _out.println("import org.apache.bcel.classfile.*;"); + _out.println("import org.apache.bcel.*;"); + _out.println("import java.io.*;"); + _out.println(); + _out.println("public class " + class_name + "Creator implements Constants {"); + _out.println(" private InstructionFactory _factory;"); + _out.println(" private ConstantPoolGen _cp;"); + _out.println(" private ClassGen _cg;"); + _out.println(); + _out.println(" public " + class_name + "Creator() {"); + _out.println(" _cg = new ClassGen(\"" + + (("".equals(package_name)) ? class_name : package_name + "." + class_name) + + "\", \"" + super_name + "\", " + "\"" + clazz.getSourceFileName() + "\", " + + printFlags(clazz.getAccessFlags(), FLAG_FOR_CLASS) + ", " + "new String[] { " + + inter + " });"); + _out.println(); + _out.println(" _cp = _cg.getConstantPool();"); + _out.println(" _factory = new InstructionFactory(_cg, _cp);"); + _out.println(" }"); + _out.println(); + printCreate(); + Field[] fields = clazz.getFields(); + if (fields.length > 0) { + _out.println(" private void createFields() {"); + _out.println(" FieldGen field;"); + for (int i = 0; i < fields.length; i++) { + fields[i].accept(this); + } + _out.println(" }"); + _out.println(); + } + Method[] methods = clazz.getMethods(); + for (int i = 0; i < methods.length; i++) { + _out.println(" private void createMethod_" + i + "() {"); + methods[i].accept(this); + _out.println(" }"); + _out.println(); + } + printMain(); + _out.println("}"); + } + + + private void printCreate() { + _out.println(" public void create(OutputStream out) throws IOException {"); + Field[] fields = _clazz.getFields(); + if (fields.length > 0) { + _out.println(" createFields();"); + } + Method[] methods = _clazz.getMethods(); + for (int i = 0; i < methods.length; i++) { + _out.println(" createMethod_" + i + "();"); + } + _out.println(" _cg.getJavaClass().dump(out);"); + _out.println(" }"); + _out.println(); + } + + + private void printMain() { + String class_name = _clazz.getClassName(); + _out.println(" public static void main(String[] args) throws Exception {"); + _out.println(" " + class_name + "Creator creator = new " + class_name + "Creator();"); + _out.println(" creator.create(new FileOutputStream(\"" + class_name + ".class\"));"); + _out.println(" }"); + } + + + public void visitField( Field field ) { + _out.println(); + _out.println(" field = new FieldGen(" + printFlags(field.getAccessFlags()) + ", " + + printType(field.getSignature()) + ", \"" + field.getName() + "\", _cp);"); + ConstantValue cv = field.getConstantValue(); + if (cv != null) { + String value = cv.toString(); + _out.println(" field.setInitValue(" + value + ")"); + } + _out.println(" _cg.addField(field.getField());"); + } + + + public void visitMethod( Method method ) { + MethodGen mg = new MethodGen(method, _clazz.getClassName(), _cp); + Type result_type = mg.getReturnType(); + Type[] arg_types = mg.getArgumentTypes(); + _out.println(" InstructionList il = new InstructionList();"); + _out.println(" MethodGen method = new MethodGen(" + + printFlags(method.getAccessFlags(), FLAG_FOR_METHOD) + ", " + + printType(result_type) + ", " + printArgumentTypes(arg_types) + ", " + + "new String[] { " + Utility.printArray(mg.getArgumentNames(), false, true) + + " }, \"" + method.getName() + "\", \"" + _clazz.getClassName() + "\", il, _cp);"); + _out.println(); + BCELFactory factory = new BCELFactory(mg, _out); + factory.start(); + _out.println(" method.setMaxStack();"); + _out.println(" method.setMaxLocals();"); + _out.println(" _cg.addMethod(method.getMethod());"); + _out.println(" il.dispose();"); + } + + + static String printFlags( int flags ) { + return printFlags(flags, FLAG_FOR_UNKNOWN); + } + + + static String printFlags( int flags, int reason ) { + if (flags == 0) { + return "0"; + } + StringBuffer buf = new StringBuffer(); + for (int i = 0, pow = 1; pow <= Constants.MAX_ACC_FLAG; i++) { + if ((flags & pow) != 0) { + if ((pow == Constants.ACC_SYNCHRONIZED) && (reason == FLAG_FOR_CLASS)) { + buf.append("ACC_SUPER | "); + } else if ((pow == Constants.ACC_VOLATILE) && (reason == FLAG_FOR_METHOD)) { + buf.append("ACC_BRIDGE | "); + } else if ((pow == Constants.ACC_TRANSIENT) && (reason == FLAG_FOR_METHOD)) { + buf.append("ACC_VARARGS | "); + } else { + buf.append("ACC_") + .append(Constants.ACCESS_NAMES[i].toUpperCase(Locale.ENGLISH)).append( + " | "); + } + } + pow <<= 1; + } + String str = buf.toString(); + return str.substring(0, str.length() - 3); + } + + + static String printArgumentTypes( Type[] arg_types ) { + if (arg_types.length == 0) { + return "Type.NO_ARGS"; + } + StringBuffer args = new StringBuffer(); + for (int i = 0; i < arg_types.length; i++) { + args.append(printType(arg_types[i])); + if (i < arg_types.length - 1) { + args.append(", "); + } + } + return "new Type[] { " + args.toString() + " }"; + } + + + static String printType( Type type ) { + return printType(type.getSignature()); + } + + + static String printType( String signature ) { + Type type = Type.getType(signature); + byte t = type.getType(); + if (t <= Constants.T_VOID) { + return "Type." + Constants.TYPE_NAMES[t].toUpperCase(Locale.ENGLISH); + } else if (type.toString().equals("java.lang.String")) { + return "Type.STRING"; + } else if (type.toString().equals("java.lang.Object")) { + return "Type.OBJECT"; + } else if (type.toString().equals("java.lang.StringBuffer")) { + return "Type.STRINGBUFFER"; + } else if (type instanceof ArrayType) { + ArrayType at = (ArrayType) type; + return "new ArrayType(" + printType(at.getBasicType()) + ", " + at.getDimensions() + + ")"; + } else { + return "new ObjectType(\"" + Utility.signatureToString(signature, false) + "\")"; + } + } + + + /** Default main method + */ + public static void main( String[] argv ) throws Exception { + JavaClass java_class; + String name = argv[0]; + if ((java_class = Repository.lookupClass(name)) == null) { + java_class = new ClassParser(name).parse(); // May throw IOException + } + BCELifier bcelifier = new BCELifier(java_class, System.out); + bcelifier.start(); + } +} diff --git a/src/org/apache/bcel/util/ByteSequence.java b/src/org/apache/bcel/util/ByteSequence.java new file mode 100644 index 0000000..e82ab2c --- /dev/null +++ b/src/org/apache/bcel/util/ByteSequence.java @@ -0,0 +1,68 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; + +/** + * Utility class that implements a sequence of bytes which can be read + * via the `readByte()' method. This is used to implement a wrapper for the + * Java byte code stream to gain some more readability. + * + * @version $Id: ByteSequence.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public final class ByteSequence extends DataInputStream { + + private ByteArrayStream byte_stream; + + + public ByteSequence(byte[] bytes) { + super(new ByteArrayStream(bytes)); + byte_stream = (ByteArrayStream) in; + } + + + public final int getIndex() { + return byte_stream.getPosition(); + } + + + final void unreadByte() { + byte_stream.unreadByte(); + } + + private static final class ByteArrayStream extends ByteArrayInputStream { + + ByteArrayStream(byte[] bytes) { + super(bytes); + } + + + final int getPosition() { + return pos; + } // is protected in ByteArrayInputStream + + + final void unreadByte() { + if (pos > 0) { + pos--; + } + } + } +} diff --git a/src/org/apache/bcel/util/Class2HTML.java b/src/org/apache/bcel/util/Class2HTML.java new file mode 100644 index 0000000..8439249 --- /dev/null +++ b/src/org/apache/bcel/util/Class2HTML.java @@ -0,0 +1,231 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.Attribute; +import org.apache.bcel.classfile.ClassParser; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.Utility; + +/** + * Read class file(s) and convert them into HTML files. + * + * Given a JavaClass object "class" that is in package "package" five files + * will be created in the specified directory. + * + *

        + *
      1. "package"."class".html as the main file which defines the frames for + * the following subfiles. + *
      2. "package"."class"_attributes.html contains all (known) attributes found in the file + *
      3. "package"."class"_cp.html contains the constant pool + *
      4. "package"."class"_code.html contains the byte code + *
      5. "package"."class"_methods.html contains references to all methods and fields of the class + *
      + * + * All subfiles reference each other appropiately, e.g. clicking on a + * method in the Method's frame will jump to the appropiate method in + * the Code frame. + * + * @version $Id: Class2HTML.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class Class2HTML implements Constants { + + private JavaClass java_class; // current class object + private String dir; + private static String class_package; // name of package, unclean to make it static, but ... + private static String class_name; // name of current class, dito + private static ConstantPool constant_pool; + + + /** + * Write contents of the given JavaClass into HTML files. + * + * @param java_class The class to write + * @param dir The directory to put the files in + */ + public Class2HTML(JavaClass java_class, String dir) throws IOException { + Method[] methods = java_class.getMethods(); + this.java_class = java_class; + this.dir = dir; + class_name = java_class.getClassName(); // Remember full name + constant_pool = java_class.getConstantPool(); + // Get package name by tacking off everything after the last `.' + int index = class_name.lastIndexOf('.'); + if (index > -1) { + class_package = class_name.substring(0, index); + } else { + class_package = ""; // default package + } + ConstantHTML constant_html = new ConstantHTML(dir, class_name, class_package, methods, + constant_pool); + /* Attributes can't be written in one step, so we just open a file + * which will be written consequently. + */ + AttributeHTML attribute_html = new AttributeHTML(dir, class_name, constant_pool, + constant_html); + MethodHTML method_html = new MethodHTML(dir, class_name, methods, java_class.getFields(), + constant_html, attribute_html); + // Write main file (with frames, yuk) + writeMainHTML(attribute_html); + new CodeHTML(dir, class_name, methods, constant_pool, constant_html); + attribute_html.close(); + } + + + public static void main( String argv[] ) { + String[] file_name = new String[argv.length]; + int files = 0; + ClassParser parser = null; + JavaClass java_class = null; + String zip_file = null; + char sep = System.getProperty("file.separator").toCharArray()[0]; + String dir = "." + sep; // Where to store HTML files + try { + /* Parse command line arguments. + */ + for (int i = 0; i < argv.length; i++) { + if (argv[i].charAt(0) == '-') { // command line switch + if (argv[i].equals("-d")) { // Specify target directory, default `. + dir = argv[++i]; + if (!dir.endsWith("" + sep)) { + dir = dir + sep; + } + new File(dir).mkdirs(); // Create target directory if necessary + } else if (argv[i].equals("-zip")) { + zip_file = argv[++i]; + } else { + System.out.println("Unknown option " + argv[i]); + } + } else { + file_name[files++] = argv[i]; + } + } + if (files == 0) { + System.err.println("Class2HTML: No input files specified."); + } else { // Loop through files ... + for (int i = 0; i < files; i++) { + System.out.print("Processing " + file_name[i] + "..."); + if (zip_file == null) { + parser = new ClassParser(file_name[i]); // Create parser object from file + } else { + parser = new ClassParser(zip_file, file_name[i]); // Create parser object from zip file + } + java_class = parser.parse(); + new Class2HTML(java_class, dir); + System.out.println("Done."); + } + } + } catch (Exception e) { + System.out.println(e); + e.printStackTrace(System.out); + } + } + + + /** + * Utility method that converts a class reference in the constant pool, + * i.e., an index to a string. + */ + static String referenceClass( int index ) { + String str = constant_pool.getConstantString(index, CONSTANT_Class); + str = Utility.compactClassName(str); + str = Utility.compactClassName(str, class_package + ".", true); + return "" + str + + ""; + } + + + static final String referenceType( String type ) { + String short_type = Utility.compactClassName(type); + short_type = Utility.compactClassName(short_type, class_package + ".", true); + int index = type.indexOf('['); // Type is an array? + String base_type = type; + if (index > -1) { + base_type = type.substring(0, index); // Tack of the `[' + } + // test for basic type + if (base_type.equals("int") || base_type.equals("short") || base_type.equals("boolean") + || base_type.equals("void") || base_type.equals("char") || base_type.equals("byte") + || base_type.equals("long") || base_type.equals("double") + || base_type.equals("float")) { + return "" + type + ""; + } else { + return "" + short_type + ""; + } + } + + + static String toHTML( String str ) { + StringBuffer buf = new StringBuffer(); + try { // Filter any characters HTML doesn't like such as < and > in particular + for (int i = 0; i < str.length(); i++) { + char ch; + switch (ch = str.charAt(i)) { + case '<': + buf.append("<"); + break; + case '>': + buf.append(">"); + break; + case '\n': + buf.append("\\n"); + break; + case '\r': + buf.append("\\r"); + break; + default: + buf.append(ch); + } + } + } catch (StringIndexOutOfBoundsException e) { + } // Never occurs + return buf.toString(); + } + + + private void writeMainHTML( AttributeHTML attribute_html ) throws IOException { + PrintWriter file = new PrintWriter(new FileOutputStream(dir + class_name + ".html")); + Attribute[] attributes = java_class.getAttributes(); + file.println("\n" + "Documentation for " + class_name + "" + + "\n" + "\n" + + "\n" + "\n" + + "\n" + "\n" + + "\n" + "\n" + + "\n" + + ""); + file.close(); + for (int i = 0; i < attributes.length; i++) { + attribute_html.writeAttribute(attributes[i], "class" + i); + } + } +} diff --git a/src/org/apache/bcel/util/ClassLoader.java b/src/org/apache/bcel/util/ClassLoader.java new file mode 100644 index 0000000..13bc041 --- /dev/null +++ b/src/org/apache/bcel/util/ClassLoader.java @@ -0,0 +1,184 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.ByteArrayInputStream; +import java.util.Hashtable; +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.ClassParser; +import org.apache.bcel.classfile.ConstantClass; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.ConstantUtf8; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Utility; + +/** + *

      Drop in replacement for the standard class loader of the JVM. You can use it + * in conjunction with the JavaWrapper to dynamically modify/create classes + * as they're requested.

      + * + *

      This class loader recognizes special requests in a distinct + * format, i.e., when the name of the requested class contains with + * "$$BCEL$$" it calls the createClass() method with that name + * (everything bevor the $$BCEL$$ is considered to be the package + * name. You can subclass the class loader and override that + * method. "Normal" classes class can be modified by overriding the + * modifyClass() method which is called just before defineClass().

      + * + *

      There may be a number of packages where you have to use the + * default class loader (which may also be faster). You can define the + * set of packages where to use the system class loader in the + * constructor. The default value contains "java.", "sun.", + * "javax."

      + * + * @version $Id: ClassLoader.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see JavaWrapper + * @see ClassPath + */ +public class ClassLoader extends java.lang.ClassLoader { + + public static final String[] DEFAULT_IGNORED_PACKAGES = { + "java.", "javax.", "sun." + }; + private Hashtable classes = new Hashtable(); // Hashtable is synchronized thus thread-safe + private String[] ignored_packages; + private Repository repository = SyntheticRepository.getInstance(); + + + /** Ignored packages are by default ( "java.", "sun.", + * "javax."), i.e. loaded by system class loader + */ + public ClassLoader() { + this(DEFAULT_IGNORED_PACKAGES); + } + + + /** @param deferTo delegate class loader to use for ignored packages + */ + public ClassLoader(java.lang.ClassLoader deferTo) { + super(deferTo); + this.ignored_packages = DEFAULT_IGNORED_PACKAGES; + this.repository = new ClassLoaderRepository(deferTo); + } + + + /** @param ignored_packages classes contained in these packages will be loaded + * with the system class loader + */ + public ClassLoader(String[] ignored_packages) { + this.ignored_packages = ignored_packages; + } + + + /** @param ignored_packages classes contained in these packages will be loaded + * with the system class loader + * @param deferTo delegate class loader to use for ignored packages + */ + public ClassLoader(java.lang.ClassLoader deferTo, String[] ignored_packages) { + this(ignored_packages); + this.repository = new ClassLoaderRepository(deferTo); + } + + + protected Class loadClass( String class_name, boolean resolve ) throws ClassNotFoundException { + Class cl = null; + /* First try: lookup hash table. + */ + if ((cl = (Class) classes.get(class_name)) == null) { + /* Second try: Load system class using system class loader. You better + * don't mess around with them. + */ + for (int i = 0; i < ignored_packages.length; i++) { + if (class_name.startsWith(ignored_packages[i])) { + cl = getParent().loadClass(class_name); + break; + } + } + if (cl == null) { + JavaClass clazz = null; + /* Third try: Special request? + */ + if (class_name.indexOf("$$BCEL$$") >= 0) { + clazz = createClass(class_name); + } else { // Fourth try: Load classes via repository + if ((clazz = repository.loadClass(class_name)) != null) { + clazz = modifyClass(clazz); + } else { + throw new ClassNotFoundException(class_name); + } + } + if (clazz != null) { + byte[] bytes = clazz.getBytes(); + cl = defineClass(class_name, bytes, 0, bytes.length); + } else { + cl = Class.forName(class_name); + } + } + if (resolve) { + resolveClass(cl); + } + } + classes.put(class_name, cl); + return cl; + } + + + /** Override this method if you want to alter a class before it gets actually + * loaded. Does nothing by default. + */ + protected JavaClass modifyClass( JavaClass clazz ) { + return clazz; + } + + + /** + * Override this method to create you own classes on the fly. The + * name contains the special token $$BCEL$$. Everything before that + * token is consddered to be a package name. You can encode you own + * arguments into the subsequent string. You must regard however not + * to use any "illegal" characters, i.e., characters that may not + * appear in a Java class name too
      + * + * The default implementation interprets the string as a encoded compressed + * Java class, unpacks and decodes it with the Utility.decode() method, and + * parses the resulting byte array and returns the resulting JavaClass object. + * + * @param class_name compressed byte code with "$$BCEL$$" in it + */ + protected JavaClass createClass( String class_name ) { + int index = class_name.indexOf("$$BCEL$$"); + String real_name = class_name.substring(index + 8); + JavaClass clazz = null; + try { + byte[] bytes = Utility.decode(real_name, true); + ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), "foo"); + clazz = parser.parse(); + } catch (Throwable e) { + e.printStackTrace(); + return null; + } + // Adapt the class name to the passed value + ConstantPool cp = clazz.getConstantPool(); + ConstantClass cl = (ConstantClass) cp.getConstant(clazz.getClassNameIndex(), + Constants.CONSTANT_Class); + ConstantUtf8 name = (ConstantUtf8) cp.getConstant(cl.getNameIndex(), + Constants.CONSTANT_Utf8); + name.setBytes(class_name.replace('.', '/')); + return clazz; + } +} diff --git a/src/org/apache/bcel/util/ClassLoaderRepository.java b/src/org/apache/bcel/util/ClassLoaderRepository.java new file mode 100644 index 0000000..75e8c63 --- /dev/null +++ b/src/org/apache/bcel/util/ClassLoaderRepository.java @@ -0,0 +1,121 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import org.apache.bcel.classfile.ClassParser; +import org.apache.bcel.classfile.JavaClass; + +/** + * The repository maintains information about which classes have + * been loaded. + * + * It loads its data from the ClassLoader implementation + * passed into its constructor. + * + * @see org.apache.bcel.Repository + * + * @version $Id: ClassLoaderRepository.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @author David Dixon-Peugh + */ +public class ClassLoaderRepository implements Repository { + + private java.lang.ClassLoader loader; + private Map loadedClasses = new HashMap(); // CLASSNAME X JAVACLASS + + + public ClassLoaderRepository(java.lang.ClassLoader loader) { + this.loader = loader; + } + + + /** + * Store a new JavaClass into this Repository. + */ + public void storeClass( JavaClass clazz ) { + loadedClasses.put(clazz.getClassName(), clazz); + clazz.setRepository(this); + } + + + /** + * Remove class from repository + */ + public void removeClass( JavaClass clazz ) { + loadedClasses.remove(clazz.getClassName()); + } + + + /** + * Find an already defined JavaClass. + */ + public JavaClass findClass( String className ) { + if (loadedClasses.containsKey(className)) { + return (JavaClass) loadedClasses.get(className); + } else { + return null; + } + } + + + /** + * Lookup a JavaClass object from the Class Name provided. + */ + public JavaClass loadClass( String className ) throws ClassNotFoundException { + String classFile = className.replace('.', '/'); + JavaClass RC = findClass(className); + if (RC != null) { + return RC; + } + try { + InputStream is = loader.getResourceAsStream(classFile + ".class"); + if (is == null) { + throw new ClassNotFoundException(className + " not found."); + } + ClassParser parser = new ClassParser(is, className); + RC = parser.parse(); + storeClass(RC); + return RC; + } catch (IOException e) { + throw new ClassNotFoundException(e.toString()); + } + } + + + public JavaClass loadClass( Class clazz ) throws ClassNotFoundException { + return loadClass(clazz.getName()); + } + + + /** Clear all entries from cache. + */ + public void clear() { + loadedClasses.clear(); + } + + + /* + * @return null + */ + public ClassPath getClassPath() { + return null; + } +} diff --git a/src/org/apache/bcel/util/ClassPath.java b/src/org/apache/bcel/util/ClassPath.java new file mode 100644 index 0000000..17d4ed1 --- /dev/null +++ b/src/org/apache/bcel/util/ClassPath.java @@ -0,0 +1,396 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * Responsible for loading (class) files from the CLASSPATH. Inspired by + * sun.tools.ClassPath. + * + * @version $Id: ClassPath.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ClassPath implements Serializable { + + public static final ClassPath SYSTEM_CLASS_PATH = new ClassPath(); + private PathEntry[] paths; + private String class_path; + + + /** + * Search for classes in given path. + */ + public ClassPath(String class_path) { + this.class_path = class_path; + List vec = new ArrayList(); + for (StringTokenizer tok = new StringTokenizer(class_path, System + .getProperty("path.separator")); tok.hasMoreTokens();) { + String path = tok.nextToken(); + if (!path.equals("")) { + File file = new File(path); + try { + if (file.exists()) { + if (file.isDirectory()) { + vec.add(new Dir(path)); + } else { + vec.add(new Zip(new ZipFile(file))); + } + } + } catch (IOException e) { + System.err.println("CLASSPATH component " + file + ": " + e); + } + } + } + paths = new PathEntry[vec.size()]; + vec.toArray(paths); + } + + + /** + * Search for classes in CLASSPATH. + * @deprecated Use SYSTEM_CLASS_PATH constant + */ + public ClassPath() { + this(getClassPath()); + } + + + /** @return used class path string + */ + public String toString() { + return class_path; + } + + + public int hashCode() { + return class_path.hashCode(); + } + + + public boolean equals( Object o ) { + if (o instanceof ClassPath) { + return class_path.equals(((ClassPath) o).class_path); + } + return false; + } + + + private static final void getPathComponents( String path, List list ) { + if (path != null) { + StringTokenizer tok = new StringTokenizer(path, File.pathSeparator); + while (tok.hasMoreTokens()) { + String name = tok.nextToken(); + File file = new File(name); + if (file.exists()) { + list.add(name); + } + } + } + } + + + /** Checks for class path components in the following properties: + * "java.class.path", "sun.boot.class.path", "java.ext.dirs" + * + * @return class path as used by default by BCEL + */ + public static final String getClassPath() { + String class_path = System.getProperty("java.class.path"); + String boot_path = System.getProperty("sun.boot.class.path"); + String ext_path = System.getProperty("java.ext.dirs"); + List list = new ArrayList(); + getPathComponents(class_path, list); + getPathComponents(boot_path, list); + List dirs = new ArrayList(); + getPathComponents(ext_path, dirs); + for (Iterator e = dirs.iterator(); e.hasNext();) { + File ext_dir = new File((String) e.next()); + String[] extensions = ext_dir.list(new FilenameFilter() { + + public boolean accept( File dir, String name ) { + name = name.toLowerCase(Locale.ENGLISH); + return name.endsWith(".zip") || name.endsWith(".jar"); + } + }); + if (extensions != null) { + for (int i = 0; i < extensions.length; i++) { + list.add(ext_dir.getPath() + File.separatorChar + extensions[i]); + } + } + } + StringBuffer buf = new StringBuffer(); + for (Iterator e = list.iterator(); e.hasNext();) { + buf.append((String) e.next()); + if (e.hasNext()) { + buf.append(File.pathSeparatorChar); + } + } + return buf.toString().intern(); + } + + + /** + * @param name fully qualified class name, e.g. java.lang.String + * @return input stream for class + */ + public InputStream getInputStream( String name ) throws IOException { + return getInputStream(name.replace('.', '/'), ".class"); + } + + + /** + * Return stream for class or resource on CLASSPATH. + * + * @param name fully qualified file name, e.g. java/lang/String + * @param suffix file name ends with suff, e.g. .java + * @return input stream for file on class path + */ + public InputStream getInputStream( String name, String suffix ) throws IOException { + InputStream is = null; + try { + is = getClass().getClassLoader().getResourceAsStream(name + suffix); + } catch (Exception e) { + } + if (is != null) { + return is; + } + return getClassFile(name, suffix).getInputStream(); + } + + + /** + * @param name fully qualified file name, e.g. java/lang/String + * @param suffix file name ends with suff, e.g. .java + * @return class file for the java class + */ + public ClassFile getClassFile( String name, String suffix ) throws IOException { + for (int i = 0; i < paths.length; i++) { + ClassFile cf; + if ((cf = paths[i].getClassFile(name, suffix)) != null) { + return cf; + } + } + throw new IOException("Couldn't find: " + name + suffix); + } + + + /** + * @param name fully qualified class name, e.g. java.lang.String + * @return input stream for class + */ + public ClassFile getClassFile( String name ) throws IOException { + return getClassFile(name, ".class"); + } + + + /** + * @param name fully qualified file name, e.g. java/lang/String + * @param suffix file name ends with suffix, e.g. .java + * @return byte array for file on class path + */ + public byte[] getBytes( String name, String suffix ) throws IOException { + DataInputStream dis = null; + try { + InputStream is = getInputStream(name, suffix); + if (is == null) { + throw new IOException("Couldn't find: " + name + suffix); + } + dis = new DataInputStream(is); + byte[] bytes = new byte[is.available()]; + dis.readFully(bytes); + return bytes; + } finally { + if (dis != null) { + dis.close(); + } + } + } + + + /** + * @return byte array for class + */ + public byte[] getBytes( String name ) throws IOException { + return getBytes(name, ".class"); + } + + + /** + * @param name name of file to search for, e.g. java/lang/String.java + * @return full (canonical) path for file + */ + public String getPath( String name ) throws IOException { + int index = name.lastIndexOf('.'); + String suffix = ""; + if (index > 0) { + suffix = name.substring(index); + name = name.substring(0, index); + } + return getPath(name, suffix); + } + + + /** + * @param name name of file to search for, e.g. java/lang/String + * @param suffix file name suffix, e.g. .java + * @return full (canonical) path for file, if it exists + */ + public String getPath( String name, String suffix ) throws IOException { + return getClassFile(name, suffix).getPath(); + } + + private static abstract class PathEntry implements Serializable { + + abstract ClassFile getClassFile( String name, String suffix ) throws IOException; + } + + /** Contains information about file/ZIP entry of the Java class. + */ + public interface ClassFile { + + /** @return input stream for class file. + */ + public abstract InputStream getInputStream() throws IOException; + + + /** @return canonical path to class file. + */ + public abstract String getPath(); + + + /** @return base path of found class, i.e. class is contained relative + * to that path, which may either denote a directory, or zip file + */ + public abstract String getBase(); + + + /** @return modification time of class file. + */ + public abstract long getTime(); + + + /** @return size of class file. + */ + public abstract long getSize(); + } + + private static class Dir extends PathEntry { + + private String dir; + + + Dir(String d) { + dir = d; + } + + + ClassFile getClassFile( String name, String suffix ) throws IOException { + final File file = new File(dir + File.separatorChar + + name.replace('.', File.separatorChar) + suffix); + return file.exists() ? new ClassFile() { + + public InputStream getInputStream() throws IOException { + return new FileInputStream(file); + } + + + public String getPath() { + try { + return file.getCanonicalPath(); + } catch (IOException e) { + return null; + } + } + + + public long getTime() { + return file.lastModified(); + } + + + public long getSize() { + return file.length(); + } + + + public String getBase() { + return dir; + } + } : null; + } + + + public String toString() { + return dir; + } + } + + private static class Zip extends PathEntry { + + private ZipFile zip; + + + Zip(ZipFile z) { + zip = z; + } + + + ClassFile getClassFile( String name, String suffix ) throws IOException { + final ZipEntry entry = zip.getEntry(name.replace('.', '/') + suffix); + return (entry != null) ? new ClassFile() { + + public InputStream getInputStream() throws IOException { + return zip.getInputStream(entry); + } + + + public String getPath() { + return entry.toString(); + } + + + public long getTime() { + return entry.getTime(); + } + + + public long getSize() { + return entry.getSize(); + } + + + public String getBase() { + return zip.getName(); + } + } : null; + } + } +} diff --git a/src/org/apache/bcel/util/ClassQueue.java b/src/org/apache/bcel/util/ClassQueue.java new file mode 100644 index 0000000..64dba0f --- /dev/null +++ b/src/org/apache/bcel/util/ClassQueue.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.util.LinkedList; +import org.apache.bcel.classfile.JavaClass; + +/** + * Utility class implementing a (typesafe) queue of JavaClass + * objects. + * + * @version $Id: ClassQueue.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + */ +public class ClassQueue implements java.io.Serializable { + + protected LinkedList vec = new LinkedList(); + + + public void enqueue( JavaClass clazz ) { + vec.addLast(clazz); + } + + + public JavaClass dequeue() { + return (JavaClass) vec.removeFirst(); + } + + + public boolean empty() { + return vec.isEmpty(); + } + + + public String toString() { + return vec.toString(); + } +} diff --git a/src/org/apache/bcel/util/ClassSet.java b/src/org/apache/bcel/util/ClassSet.java new file mode 100644 index 0000000..21774fd --- /dev/null +++ b/src/org/apache/bcel/util/ClassSet.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import org.apache.bcel.classfile.JavaClass; + +/** + * Utility class implementing a (typesafe) set of JavaClass objects. + * Since JavaClass has no equals() method, the name of the class is + * used for comparison. + * + * @version $Id: ClassSet.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see ClassStack + */ +public class ClassSet implements java.io.Serializable { + + private Map _map = new HashMap(); + + + public boolean add( JavaClass clazz ) { + boolean result = false; + if (!_map.containsKey(clazz.getClassName())) { + result = true; + _map.put(clazz.getClassName(), clazz); + } + return result; + } + + + public void remove( JavaClass clazz ) { + _map.remove(clazz.getClassName()); + } + + + public boolean empty() { + return _map.isEmpty(); + } + + + public JavaClass[] toArray() { + Collection values = _map.values(); + JavaClass[] classes = new JavaClass[values.size()]; + values.toArray(classes); + return classes; + } + + + public String[] getClassNames() { + return (String[]) _map.keySet().toArray(new String[_map.keySet().size()]); + } +} diff --git a/src/org/apache/bcel/util/ClassStack.java b/src/org/apache/bcel/util/ClassStack.java new file mode 100644 index 0000000..a6c3411 --- /dev/null +++ b/src/org/apache/bcel/util/ClassStack.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.util.Stack; +import org.apache.bcel.classfile.JavaClass; + +/** + * Utility class implementing a (typesafe) stack of JavaClass objects. + * + * @version $Id: ClassStack.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Stack + */ +public class ClassStack implements java.io.Serializable { + + private Stack stack = new Stack(); + + + public void push( JavaClass clazz ) { + stack.push(clazz); + } + + + public JavaClass pop() { + return (JavaClass) stack.pop(); + } + + + public JavaClass top() { + return (JavaClass) stack.peek(); + } + + + public boolean empty() { + return stack.empty(); + } +} diff --git a/src/org/apache/bcel/util/ClassVector.java b/src/org/apache/bcel/util/ClassVector.java new file mode 100644 index 0000000..8ac922a --- /dev/null +++ b/src/org/apache/bcel/util/ClassVector.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.util.ArrayList; +import java.util.List; +import org.apache.bcel.classfile.JavaClass; + +/** + * Utility class implementing a (typesafe) collection of JavaClass + * objects. Contains the most important methods of a Vector. + * + * @version $Id: ClassVector.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * + * @deprecated as of 5.1.1 - 7/17/2005 + */ +public class ClassVector implements java.io.Serializable { + + protected List vec = new ArrayList(); + + + public void addElement( JavaClass clazz ) { + vec.add(clazz); + } + + + public JavaClass elementAt( int index ) { + return (JavaClass) vec.get(index); + } + + + public void removeElementAt( int index ) { + vec.remove(index); + } + + + public JavaClass[] toArray() { + JavaClass[] classes = new JavaClass[vec.size()]; + vec.toArray(classes); + return classes; + } +} diff --git a/src/org/apache/bcel/util/CodeHTML.java b/src/org/apache/bcel/util/CodeHTML.java new file mode 100644 index 0000000..4b44011 --- /dev/null +++ b/src/org/apache/bcel/util/CodeHTML.java @@ -0,0 +1,564 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.BitSet; +import org.apache.bcel.classfile.Attribute; +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.CodeException; +import org.apache.bcel.classfile.ConstantFieldref; +import org.apache.bcel.classfile.ConstantInterfaceMethodref; +import org.apache.bcel.classfile.ConstantMethodref; +import org.apache.bcel.classfile.ConstantNameAndType; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.LocalVariable; +import org.apache.bcel.classfile.LocalVariableTable; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.Utility; + +/** + * Convert code into HTML file. + * + * @version $Id: CodeHTML.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * + */ +final class CodeHTML implements org.apache.bcel.Constants { + + private String class_name; // name of current class + private Method[] methods; // Methods to print + private PrintWriter file; // file to write to + private BitSet goto_set; + private ConstantPool constant_pool; + private ConstantHTML constant_html; + private static boolean wide = false; + + + CodeHTML(String dir, String class_name, Method[] methods, ConstantPool constant_pool, + ConstantHTML constant_html) throws IOException { + this.class_name = class_name; + this.methods = methods; + this.constant_pool = constant_pool; + this.constant_html = constant_html; + file = new PrintWriter(new FileOutputStream(dir + class_name + "_code.html")); + file.println(""); + for (int i = 0; i < methods.length; i++) { + writeMethod(methods[i], i); + } + file.println(""); + file.close(); + } + + + /** + * Disassemble a stream of byte codes and return the + * string representation. + * + * @param stream data input stream + * @return String representation of byte code + */ + private final String codeToHTML( ByteSequence bytes, int method_number ) throws IOException { + short opcode = (short) bytes.readUnsignedByte(); + StringBuffer buf; + String name, signature; + int default_offset = 0, low, high; + int index, class_index, vindex, constant; + int[] jump_table; + int no_pad_bytes = 0, offset; + buf = new StringBuffer(256); + buf.append("").append(OPCODE_NAMES[opcode]).append(""); + /* Special case: Skip (0-3) padding bytes, i.e., the + * following bytes are 4-byte-aligned + */ + if ((opcode == TABLESWITCH) || (opcode == LOOKUPSWITCH)) { + int remainder = bytes.getIndex() % 4; + no_pad_bytes = (remainder == 0) ? 0 : 4 - remainder; + for (int i = 0; i < no_pad_bytes; i++) { + bytes.readByte(); + } + // Both cases have a field default_offset in common + default_offset = bytes.readInt(); + } + switch (opcode) { + case TABLESWITCH: + low = bytes.readInt(); + high = bytes.readInt(); + offset = bytes.getIndex() - 12 - no_pad_bytes - 1; + default_offset += offset; + buf.append(""); + // Print switch indices in first row (and default) + jump_table = new int[high - low + 1]; + for (int i = 0; i < jump_table.length; i++) { + jump_table[i] = offset + bytes.readInt(); + buf.append(""); + } + buf.append("\n"); + // Print target and default indices in second row + for (int i = 0; i < jump_table.length; i++) { + buf.append(""); + } + buf.append("\n
      ").append(low + i).append("default
      ").append(jump_table[i]).append("").append(default_offset).append( + "
      \n"); + break; + /* Lookup switch has variable length arguments. + */ + case LOOKUPSWITCH: + int npairs = bytes.readInt(); + offset = bytes.getIndex() - 8 - no_pad_bytes - 1; + jump_table = new int[npairs]; + default_offset += offset; + buf.append(""); + // Print switch indices in first row (and default) + for (int i = 0; i < npairs; i++) { + int match = bytes.readInt(); + jump_table[i] = offset + bytes.readInt(); + buf.append(""); + } + buf.append("\n"); + // Print target and default indices in second row + for (int i = 0; i < npairs; i++) { + buf.append(""); + } + buf.append("\n
      ").append(match).append("default
      ").append(jump_table[i]).append("").append(default_offset).append( + "
      \n"); + break; + /* Two address bytes + offset from start of byte stream form the + * jump target. + */ + case GOTO: + case IFEQ: + case IFGE: + case IFGT: + case IFLE: + case IFLT: + case IFNE: + case IFNONNULL: + case IFNULL: + case IF_ACMPEQ: + case IF_ACMPNE: + case IF_ICMPEQ: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ICMPLT: + case IF_ICMPNE: + case JSR: + index = (int) (bytes.getIndex() + bytes.readShort() - 1); + buf.append("").append(index).append(""); + break; + /* Same for 32-bit wide jumps + */ + case GOTO_W: + case JSR_W: + int windex = bytes.getIndex() + bytes.readInt() - 1; + buf.append("").append(windex).append(""); + break; + /* Index byte references local variable (register) + */ + case ALOAD: + case ASTORE: + case DLOAD: + case DSTORE: + case FLOAD: + case FSTORE: + case ILOAD: + case ISTORE: + case LLOAD: + case LSTORE: + case RET: + if (wide) { + vindex = bytes.readShort(); + wide = false; // Clear flag + } else { + vindex = bytes.readUnsignedByte(); + } + buf.append("%").append(vindex); + break; + /* + * Remember wide byte which is used to form a 16-bit address in the + * following instruction. Relies on that the method is called again with + * the following opcode. + */ + case WIDE: + wide = true; + buf.append("(wide)"); + break; + /* Array of basic type. + */ + case NEWARRAY: + buf.append("").append(TYPE_NAMES[bytes.readByte()]).append( + ""); + break; + /* Access object/class fields. + */ + case GETFIELD: + case GETSTATIC: + case PUTFIELD: + case PUTSTATIC: + index = bytes.readShort(); + ConstantFieldref c1 = (ConstantFieldref) constant_pool.getConstant(index, + CONSTANT_Fieldref); + class_index = c1.getClassIndex(); + name = constant_pool.getConstantString(class_index, CONSTANT_Class); + name = Utility.compactClassName(name, false); + index = c1.getNameAndTypeIndex(); + String field_name = constant_pool.constantToString(index, CONSTANT_NameAndType); + if (name.equals(class_name)) { // Local field + buf.append("").append(field_name) + .append("\n"); + } else { + buf.append(constant_html.referenceConstant(class_index)).append(".").append( + field_name); + } + break; + /* Operands are references to classes in constant pool + */ + case CHECKCAST: + case INSTANCEOF: + case NEW: + index = bytes.readShort(); + buf.append(constant_html.referenceConstant(index)); + break; + /* Operands are references to methods in constant pool + */ + case INVOKESPECIAL: + case INVOKESTATIC: + case INVOKEVIRTUAL: + case INVOKEINTERFACE: + int m_index = bytes.readShort(); + String str; + if (opcode == INVOKEINTERFACE) { // Special treatment needed + int nargs = bytes.readUnsignedByte(); // Redundant + int reserved = bytes.readUnsignedByte(); // Reserved + ConstantInterfaceMethodref c = (ConstantInterfaceMethodref) constant_pool + .getConstant(m_index, CONSTANT_InterfaceMethodref); + class_index = c.getClassIndex(); + str = constant_pool.constantToString(c); + index = c.getNameAndTypeIndex(); + } else { + ConstantMethodref c = (ConstantMethodref) constant_pool.getConstant(m_index, + CONSTANT_Methodref); + class_index = c.getClassIndex(); + str = constant_pool.constantToString(c); + index = c.getNameAndTypeIndex(); + } + name = Class2HTML.referenceClass(class_index); + str = Class2HTML.toHTML(constant_pool.constantToString(constant_pool.getConstant( + index, CONSTANT_NameAndType))); + // Get signature, i.e., types + ConstantNameAndType c2 = (ConstantNameAndType) constant_pool.getConstant(index, + CONSTANT_NameAndType); + signature = constant_pool.constantToString(c2.getSignatureIndex(), CONSTANT_Utf8); + String[] args = Utility.methodSignatureArgumentTypes(signature, false); + String type = Utility.methodSignatureReturnType(signature, false); + buf.append(name).append(".").append(str).append( + "").append("("); + // List arguments + for (int i = 0; i < args.length; i++) { + buf.append(Class2HTML.referenceType(args[i])); + if (i < args.length - 1) { + buf.append(", "); + } + } + // Attach return type + buf.append("):").append(Class2HTML.referenceType(type)); + break; + /* Operands are references to items in constant pool + */ + case LDC_W: + case LDC2_W: + index = bytes.readShort(); + buf.append("").append( + Class2HTML.toHTML(constant_pool.constantToString(index, + constant_pool.getConstant(index).getTag()))).append(""); + break; + case LDC: + index = bytes.readUnsignedByte(); + buf.append("").append( + Class2HTML.toHTML(constant_pool.constantToString(index, + constant_pool.getConstant(index).getTag()))).append(""); + break; + /* Array of references. + */ + case ANEWARRAY: + index = bytes.readShort(); + buf.append(constant_html.referenceConstant(index)); + break; + /* Multidimensional array of references. + */ + case MULTIANEWARRAY: + index = bytes.readShort(); + int dimensions = bytes.readByte(); + buf.append(constant_html.referenceConstant(index)).append(":").append(dimensions) + .append("-dimensional"); + break; + /* Increment local variable. + */ + case IINC: + if (wide) { + vindex = bytes.readShort(); + constant = bytes.readShort(); + wide = false; + } else { + vindex = bytes.readUnsignedByte(); + constant = bytes.readByte(); + } + buf.append("%").append(vindex).append(" ").append(constant); + break; + default: + if (NO_OF_OPERANDS[opcode] > 0) { + for (int i = 0; i < TYPE_OF_OPERANDS[opcode].length; i++) { + switch (TYPE_OF_OPERANDS[opcode][i]) { + case T_BYTE: + buf.append(bytes.readUnsignedByte()); + break; + case T_SHORT: // Either branch or index + buf.append(bytes.readShort()); + break; + case T_INT: + buf.append(bytes.readInt()); + break; + default: // Never reached + System.err.println("Unreachable default case reached!"); + System.exit(-1); + } + buf.append(" "); + } + } + } + buf.append(""); + return buf.toString(); + } + + + /** + * Find all target addresses in code, so that they can be marked + * with <A NAME = ...>. Target addresses are kept in an BitSet object. + */ + private final void findGotos( ByteSequence bytes, Method method, Code code ) throws IOException { + int index; + goto_set = new BitSet(bytes.available()); + int opcode; + /* First get Code attribute from method and the exceptions handled + * (try .. catch) in this method. We only need the line number here. + */ + if (code != null) { + CodeException[] ce = code.getExceptionTable(); + int len = ce.length; + for (int i = 0; i < len; i++) { + goto_set.set(ce[i].getStartPC()); + goto_set.set(ce[i].getEndPC()); + goto_set.set(ce[i].getHandlerPC()); + } + // Look for local variables and their range + Attribute[] attributes = code.getAttributes(); + for (int i = 0; i < attributes.length; i++) { + if (attributes[i].getTag() == ATTR_LOCAL_VARIABLE_TABLE) { + LocalVariable[] vars = ((LocalVariableTable) attributes[i]) + .getLocalVariableTable(); + for (int j = 0; j < vars.length; j++) { + int start = vars[j].getStartPC(); + int end = (int) (start + vars[j].getLength()); + goto_set.set(start); + goto_set.set(end); + } + break; + } + } + } + // Get target addresses from GOTO, JSR, TABLESWITCH, etc. + for (int i = 0; bytes.available() > 0; i++) { + opcode = bytes.readUnsignedByte(); + //System.out.println(OPCODE_NAMES[opcode]); + switch (opcode) { + case TABLESWITCH: + case LOOKUPSWITCH: + //bytes.readByte(); // Skip already read byte + int remainder = bytes.getIndex() % 4; + int no_pad_bytes = (remainder == 0) ? 0 : 4 - remainder; + int default_offset, + offset; + for (int j = 0; j < no_pad_bytes; j++) { + bytes.readByte(); + } + // Both cases have a field default_offset in common + default_offset = bytes.readInt(); + if (opcode == TABLESWITCH) { + int low = bytes.readInt(); + int high = bytes.readInt(); + offset = bytes.getIndex() - 12 - no_pad_bytes - 1; + default_offset += offset; + goto_set.set(default_offset); + for (int j = 0; j < (high - low + 1); j++) { + index = offset + bytes.readInt(); + goto_set.set(index); + } + } else { // LOOKUPSWITCH + int npairs = bytes.readInt(); + offset = bytes.getIndex() - 8 - no_pad_bytes - 1; + default_offset += offset; + goto_set.set(default_offset); + for (int j = 0; j < npairs; j++) { + int match = bytes.readInt(); + index = offset + bytes.readInt(); + goto_set.set(index); + } + } + break; + case GOTO: + case IFEQ: + case IFGE: + case IFGT: + case IFLE: + case IFLT: + case IFNE: + case IFNONNULL: + case IFNULL: + case IF_ACMPEQ: + case IF_ACMPNE: + case IF_ICMPEQ: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ICMPLT: + case IF_ICMPNE: + case JSR: + //bytes.readByte(); // Skip already read byte + index = bytes.getIndex() + bytes.readShort() - 1; + goto_set.set(index); + break; + case GOTO_W: + case JSR_W: + //bytes.readByte(); // Skip already read byte + index = bytes.getIndex() + bytes.readInt() - 1; + goto_set.set(index); + break; + default: + bytes.unreadByte(); + codeToHTML(bytes, 0); // Ignore output + } + } + } + + + /** + * Write a single method with the byte code associated with it. + */ + private void writeMethod( Method method, int method_number ) throws IOException { + // Get raw signature + String signature = method.getSignature(); + // Get array of strings containing the argument types + String[] args = Utility.methodSignatureArgumentTypes(signature, false); + // Get return type string + String type = Utility.methodSignatureReturnType(signature, false); + // Get method name + String name = method.getName(); + String html_name = Class2HTML.toHTML(name); + // Get method's access flags + String access = Utility.accessToString(method.getAccessFlags()); + access = Utility.replace(access, " ", " "); + // Get the method's attributes, the Code Attribute in particular + Attribute[] attributes = method.getAttributes(); + file.print("

      " + access + " " + "" + Class2HTML.referenceType(type) + " " + + html_name + "("); + for (int i = 0; i < args.length; i++) { + file.print(Class2HTML.referenceType(args[i])); + if (i < args.length - 1) { + file.print(", "); + } + } + file.println(")

      "); + Code c = null; + byte[] code = null; + if (attributes.length > 0) { + file.print("

      Attributes

        \n"); + for (int i = 0; i < attributes.length; i++) { + byte tag = attributes[i].getTag(); + if (tag != ATTR_UNKNOWN) { + file.print("
      • " + + ATTRIBUTE_NAMES[tag] + "
      • \n"); + } else { + file.print("
      • " + attributes[i] + "
      • "); + } + if (tag == ATTR_CODE) { + c = (Code) attributes[i]; + Attribute[] attributes2 = c.getAttributes(); + code = c.getCode(); + file.print("
          "); + for (int j = 0; j < attributes2.length; j++) { + tag = attributes2[j].getTag(); + file.print("
        • " + + ATTRIBUTE_NAMES[tag] + "
        • \n"); + } + file.print("
        "); + } + } + file.println("
      "); + } + if (code != null) { // No code, an abstract method, e.g. + //System.out.println(name + "\n" + Utility.codeToString(code, constant_pool, 0, -1)); + // Print the byte code + ByteSequence stream = new ByteSequence(code); + stream.mark(stream.available()); + findGotos(stream, method, c); + stream.reset(); + file.println("" + + ""); + for (int i = 0; stream.available() > 0; i++) { + int offset = stream.getIndex(); + String str = codeToHTML(stream, method_number); + String anchor = ""; + /* Set an anchor mark if this line is targetted by a goto, jsr, etc. + * Defining an anchor for every line is very inefficient! + */ + if (goto_set.get(offset)) { + anchor = ""; + } + String anchor2; + if (stream.getIndex() == code.length) { + anchor2 = "" + offset + + ""; + } else { + anchor2 = "" + offset; + } + file + .println(""); + } + // Mark last line, may be targetted from Attributes window + file.println(""); + file.println("
      Byte
      offset
      InstructionArgument
      " + anchor2 + "" + anchor + str + + "
      "); + } + } +} diff --git a/src/org/apache/bcel/util/ConstantHTML.java b/src/org/apache/bcel/util/ConstantHTML.java new file mode 100644 index 0000000..f543bf4 --- /dev/null +++ b/src/org/apache/bcel/util/ConstantHTML.java @@ -0,0 +1,234 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.classfile.ConstantClass; +import org.apache.bcel.classfile.ConstantFieldref; +import org.apache.bcel.classfile.ConstantInterfaceMethodref; +import org.apache.bcel.classfile.ConstantMethodref; +import org.apache.bcel.classfile.ConstantNameAndType; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.ConstantString; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.Utility; + +/** + * Convert constant pool into HTML file. + * + * @version $Id: ConstantHTML.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * + */ +final class ConstantHTML implements org.apache.bcel.Constants { + + private String class_name; // name of current class + private String class_package; // name of package + private ConstantPool constant_pool; // reference to constant pool + private PrintWriter file; // file to write to + private String[] constant_ref; // String to return for cp[i] + private Constant[] constants; // The constants in the cp + private Method[] methods; + + + ConstantHTML(String dir, String class_name, String class_package, Method[] methods, + ConstantPool constant_pool) throws IOException { + this.class_name = class_name; + this.class_package = class_package; + this.constant_pool = constant_pool; + this.methods = methods; + constants = constant_pool.getConstantPool(); + file = new PrintWriter(new FileOutputStream(dir + class_name + "_cp.html")); + constant_ref = new String[constants.length]; + constant_ref[0] = "<unknown>"; + file.println(""); + // Loop through constants, constants[0] is reserved + for (int i = 1; i < constants.length; i++) { + if (i % 2 == 0) { + file.print("\n"); + } + file.println("
      "); + } else { + file.print("
      "); + } + if (constants[i] != null) { + writeConstant(i); + } + file.print("
      "); + file.close(); + } + + + String referenceConstant( int index ) { + return constant_ref[index]; + } + + + private void writeConstant( int index ) { + byte tag = constants[index].getTag(); + int class_index, name_index; + String ref; + // The header is always the same + file.println("

      " + index + " " + CONSTANT_NAMES[tag] + + "

      "); + /* For every constant type get the needed parameters and print them appropiately + */ + switch (tag) { + case CONSTANT_InterfaceMethodref: + case CONSTANT_Methodref: + // Get class_index and name_and_type_index, depending on type + if (tag == CONSTANT_Methodref) { + ConstantMethodref c = (ConstantMethodref) constant_pool.getConstant(index, + CONSTANT_Methodref); + class_index = c.getClassIndex(); + name_index = c.getNameAndTypeIndex(); + } else { + ConstantInterfaceMethodref c1 = (ConstantInterfaceMethodref) constant_pool + .getConstant(index, CONSTANT_InterfaceMethodref); + class_index = c1.getClassIndex(); + name_index = c1.getNameAndTypeIndex(); + } + // Get method name and its class + String method_name = constant_pool.constantToString(name_index, + CONSTANT_NameAndType); + String html_method_name = Class2HTML.toHTML(method_name); + // Partially compacted class name, i.e., / -> . + String method_class = constant_pool.constantToString(class_index, CONSTANT_Class); + String short_method_class = Utility.compactClassName(method_class); // I.e., remove java.lang. + short_method_class = Utility.compactClassName(method_class); // I.e., remove java.lang. + short_method_class = Utility.compactClassName(short_method_class, class_package + + ".", true); // Remove class package prefix + // Get method signature + ConstantNameAndType c2 = (ConstantNameAndType) constant_pool.getConstant( + name_index, CONSTANT_NameAndType); + String signature = constant_pool.constantToString(c2.getSignatureIndex(), + CONSTANT_Utf8); + // Get array of strings containing the argument types + String[] args = Utility.methodSignatureArgumentTypes(signature, false); + // Get return type string + String type = Utility.methodSignatureReturnType(signature, false); + String ret_type = Class2HTML.referenceType(type); + StringBuffer buf = new StringBuffer("("); + for (int i = 0; i < args.length; i++) { + buf.append(Class2HTML.referenceType(args[i])); + if (i < args.length - 1) { + buf.append(", "); + } + } + buf.append(")"); + String arg_types = buf.toString(); + if (method_class.equals(class_name)) { + ref = "" + + html_method_name + ""; + } else { + ref = "" + + short_method_class + "." + html_method_name; + } + constant_ref[index] = ret_type + " " + short_method_class + + "." + html_method_name + " " + arg_types; + file.println("

      " + ret_type + " " + ref + arg_types + + " \n

      "); + break; + case CONSTANT_Fieldref: + // Get class_index and name_and_type_index + ConstantFieldref c3 = (ConstantFieldref) constant_pool.getConstant(index, + CONSTANT_Fieldref); + class_index = c3.getClassIndex(); + name_index = c3.getNameAndTypeIndex(); + // Get method name and its class (compacted) + String field_class = constant_pool.constantToString(class_index, CONSTANT_Class); + String short_field_class = Utility.compactClassName(field_class); // I.e., remove java.lang. + short_field_class = Utility.compactClassName(short_field_class, + class_package + ".", true); // Remove class package prefix + String field_name = constant_pool + .constantToString(name_index, CONSTANT_NameAndType); + if (field_class.equals(class_name)) { + ref = "" + field_name + ""; + } else { + ref = "" + short_field_class + + "." + field_name + "\n"; + } + constant_ref[index] = "" + short_field_class + "." + + field_name + ""; + file.println("

      " + ref + "
      \n" + "

      "); + break; + case CONSTANT_Class: + ConstantClass c4 = (ConstantClass) constant_pool.getConstant(index, CONSTANT_Class); + name_index = c4.getNameIndex(); + String class_name2 = constant_pool.constantToString(index, tag); // / -> . + String short_class_name = Utility.compactClassName(class_name2); // I.e., remove java.lang. + short_class_name = Utility.compactClassName(short_class_name, class_package + ".", + true); // Remove class package prefix + ref = "" + short_class_name + + ""; + constant_ref[index] = "" + short_class_name + ""; + file.println("

      " + ref + "

      \n"); + break; + case CONSTANT_String: + ConstantString c5 = (ConstantString) constant_pool.getConstant(index, + CONSTANT_String); + name_index = c5.getStringIndex(); + String str = Class2HTML.toHTML(constant_pool.constantToString(index, tag)); + file.println("

      " + str + "

      \n"); + break; + case CONSTANT_NameAndType: + ConstantNameAndType c6 = (ConstantNameAndType) constant_pool.getConstant(index, + CONSTANT_NameAndType); + name_index = c6.getNameIndex(); + int signature_index = c6.getSignatureIndex(); + file.println("

      " + + Class2HTML.toHTML(constant_pool.constantToString(index, tag)) + + "

      \n"); + break; + default: + file + .println("

      " + + Class2HTML.toHTML(constant_pool.constantToString(index, tag)) + + "\n"); + } // switch + } + + + private final int getMethodNumber( String str ) { + for (int i = 0; i < methods.length; i++) { + String cmp = methods[i].getName() + methods[i].getSignature(); + if (cmp.equals(str)) { + return i; + } + } + return -1; + } +} diff --git a/src/org/apache/bcel/util/InstructionFinder.java b/src/org/apache/bcel/util/InstructionFinder.java new file mode 100644 index 0000000..79982bf --- /dev/null +++ b/src/org/apache/bcel/util/InstructionFinder.java @@ -0,0 +1,472 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.bcel.Constants; +import org.apache.bcel.generic.ClassGenException; +import org.apache.bcel.generic.Instruction; +import org.apache.bcel.generic.InstructionHandle; +import org.apache.bcel.generic.InstructionList; + +/** + * InstructionFinder is a tool to search for given instructions patterns, i.e., + * match sequences of instructions in an instruction list via regular + * expressions. This can be used, e.g., in order to implement a peep hole + * optimizer that looks for code patterns and replaces them with faster + * equivalents. + * + *

      + * This class internally uses the + * Regexp package to search for regular expressions. + * + * A typical application would look like this: + * + *

      + * 
      + *  
      + *   InstructionFinder f   = new InstructionFinder(il);
      + *   String            pat = "IfInstruction ICONST_0 GOTO ICONST_1 NOP (IFEQ|IFNE)";
      + *   
      + *   for(Iterator i = f.search(pat, constraint); i.hasNext(); ) {
      + *   InstructionHandle[] match = (InstructionHandle[])i.next();
      + *   ...
      + *   il.delete(match[1], match[5]);
      + *   ...
      + *   }
      + *   
      + *  
      + * 
      + * + * @version $Id: InstructionFinder.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see Instruction + * @see InstructionList + */ +public class InstructionFinder { + + private static final int OFFSET = 32767; // char + OFFSET is + // outside of + // LATIN-1 + private static final int NO_OPCODES = 256; // Potential number, + // some are not used + private static final Map map = new HashMap(); // Map + private InstructionList il; + private String il_string; // instruction list + // as string + private InstructionHandle[] handles; // map instruction + + + // list to array + /** + * @param il + * instruction list to search for given patterns + */ + public InstructionFinder(InstructionList il) { + this.il = il; + reread(); + } + + + /** + * Reread the instruction list, e.g., after you've altered the list upon a + * match. + */ + public final void reread() { + int size = il.getLength(); + char[] buf = new char[size]; // Create a string with length equal to il + // length + handles = il.getInstructionHandles(); + // Map opcodes to characters + for (int i = 0; i < size; i++) { + buf[i] = makeChar(handles[i].getInstruction().getOpcode()); + } + il_string = new String(buf); + } + + + /** + * Map symbolic instruction names like "getfield" to a single character. + * + * @param pattern + * instruction pattern in lower case + * @return encoded string for a pattern such as "BranchInstruction". + */ + private static final String mapName( String pattern ) { + String result = (String) map.get(pattern); + if (result != null) { + return result; + } + for (short i = 0; i < NO_OPCODES; i++) { + if (pattern.equals(Constants.OPCODE_NAMES[i])) { + return "" + makeChar(i); + } + } + throw new RuntimeException("Instruction unknown: " + pattern); + } + + + /** + * Replace symbolic names of instructions with the appropiate character and + * remove all white space from string. Meta characters such as +, * are + * ignored. + * + * @param pattern + * The pattern to compile + * @return translated regular expression string + */ + private static final String compilePattern( String pattern ) { + //Bug: 38787 - Instructions are assumed to be english, to avoid odd Locale issues + String lower = pattern.toLowerCase(Locale.ENGLISH); + StringBuffer buf = new StringBuffer(); + int size = pattern.length(); + for (int i = 0; i < size; i++) { + char ch = lower.charAt(i); + if (Character.isLetterOrDigit(ch)) { + StringBuffer name = new StringBuffer(); + while ((Character.isLetterOrDigit(ch) || ch == '_') && i < size) { + name.append(ch); + if (++i < size) { + ch = lower.charAt(i); + } else { + break; + } + } + i--; + buf.append(mapName(name.toString())); + } else if (!Character.isWhitespace(ch)) { + buf.append(ch); + } + } + return buf.toString(); + } + + + /** + * @return the matched piece of code as an array of instruction (handles) + */ + private InstructionHandle[] getMatch( int matched_from, int match_length ) { + InstructionHandle[] match = new InstructionHandle[match_length]; + System.arraycopy(handles, matched_from, match, 0, match_length); + return match; + } + + + /** + * Search for the given pattern in the instruction list. You can search for + * any valid opcode via its symbolic name, e.g. "istore". You can also use a + * super class or an interface name to match a whole set of instructions, e.g. + * "BranchInstruction" or "LoadInstruction". "istore" is also an alias for all + * "istore_x" instructions. Additional aliases are "if" for "ifxx", "if_icmp" + * for "if_icmpxx", "if_acmp" for "if_acmpxx". + * + * Consecutive instruction names must be separated by white space which will + * be removed during the compilation of the pattern. + * + * For the rest the usual pattern matching rules for regular expressions + * apply. + *

      + * Example pattern: + * + *

      +     * search("BranchInstruction NOP ((IfInstruction|GOTO)+ ISTORE Instruction)*");
      +     * 
      + * + *

      + * If you alter the instruction list upon a match such that other matching + * areas are affected, you should call reread() to update the finder and call + * search() again, because the matches are cached. + * + * @param pattern + * the instruction pattern to search for, where case is ignored + * @param from + * where to start the search in the instruction list + * @param constraint + * optional CodeConstraint to check the found code pattern for + * user-defined constraints + * @return iterator of matches where e.nextElement() returns an array of + * instruction handles describing the matched area + */ + public final Iterator search( String pattern, InstructionHandle from, CodeConstraint constraint ) { + String search = compilePattern(pattern); + int start = -1; + for (int i = 0; i < handles.length; i++) { + if (handles[i] == from) { + start = i; // Where to start search from (index) + break; + } + } + if (start == -1) { + throw new ClassGenException("Instruction handle " + from + + " not found in instruction list."); + } + Pattern regex = Pattern.compile(search); + List matches = new ArrayList(); + Matcher matcher = regex.matcher(il_string); + while (start < il_string.length() && matcher.find(start)) { + int startExpr = matcher.start(); + int endExpr = matcher.end(); + int lenExpr = (endExpr - startExpr) + 1; + InstructionHandle[] match = getMatch(startExpr, lenExpr); + if ((constraint == null) || constraint.checkCode(match)) { + matches.add(match); + } + start = endExpr; + } + return matches.iterator(); + } + + + /** + * Start search beginning from the start of the given instruction list. + * + * @param pattern + * the instruction pattern to search for, where case is ignored + * @return iterator of matches where e.nextElement() returns an array of + * instruction handles describing the matched area + */ + public final Iterator search( String pattern ) { + return search(pattern, il.getStart(), null); + } + + + /** + * Start search beginning from `from'. + * + * @param pattern + * the instruction pattern to search for, where case is ignored + * @param from + * where to start the search in the instruction list + * @return iterator of matches where e.nextElement() returns an array of + * instruction handles describing the matched area + */ + public final Iterator search( String pattern, InstructionHandle from ) { + return search(pattern, from, null); + } + + + /** + * Start search beginning from the start of the given instruction list. Check + * found matches with the constraint object. + * + * @param pattern + * the instruction pattern to search for, case is ignored + * @param constraint + * constraints to be checked on matching code + * @return instruction handle or `null' if the match failed + */ + public final Iterator search( String pattern, CodeConstraint constraint ) { + return search(pattern, il.getStart(), constraint); + } + + + /** + * Convert opcode number to char. + */ + private static final char makeChar( short opcode ) { + return (char) (opcode + OFFSET); + } + + + /** + * @return the inquired instruction list + */ + public final InstructionList getInstructionList() { + return il; + } + + /** + * Code patterns found may be checked using an additional user-defined + * constraint object whether they really match the needed criterion. I.e., + * check constraints that can not expressed with regular expressions. + * + */ + public static interface CodeConstraint { + + /** + * @param match + * array of instructions matching the requested pattern + * @return true if the matched area is really useful + */ + public boolean checkCode( InstructionHandle[] match ); + } + + // Initialize pattern map + static { + map + .put( + "arithmeticinstruction", + "(irem|lrem|iand|ior|ineg|isub|lneg|fneg|fmul|ldiv|fadd|lxor|frem|idiv|land|ixor|ishr|fsub|lshl|fdiv|iadd|lor|dmul|lsub|ishl|imul|lmul|lushr|dneg|iushr|lshr|ddiv|drem|dadd|ladd|dsub)"); + map.put("invokeinstruction", "(invokevirtual|invokeinterface|invokestatic|invokespecial)"); + map + .put( + "arrayinstruction", + "(baload|aastore|saload|caload|fastore|lastore|iaload|castore|iastore|aaload|bastore|sastore|faload|laload|daload|dastore)"); + map.put("gotoinstruction", "(goto|goto_w)"); + map.put("conversioninstruction", + "(d2l|l2d|i2s|d2i|l2i|i2b|l2f|d2f|f2i|i2d|i2l|f2d|i2c|f2l|i2f)"); + map.put("localvariableinstruction", + "(fstore|iinc|lload|dstore|dload|iload|aload|astore|istore|fload|lstore)"); + map.put("loadinstruction", "(fload|dload|lload|iload|aload)"); + map.put("fieldinstruction", "(getfield|putstatic|getstatic|putfield)"); + map + .put( + "cpinstruction", + "(ldc2_w|invokeinterface|multianewarray|putstatic|instanceof|getstatic|checkcast|getfield|invokespecial|ldc_w|invokestatic|invokevirtual|putfield|ldc|new|anewarray)"); + map.put("stackinstruction", "(dup2|swap|dup2_x2|pop|pop2|dup|dup2_x1|dup_x2|dup_x1)"); + map + .put( + "branchinstruction", + "(ifle|if_acmpne|if_icmpeq|if_acmpeq|ifnonnull|goto_w|iflt|ifnull|if_icmpne|tableswitch|if_icmple|ifeq|if_icmplt|jsr_w|if_icmpgt|ifgt|jsr|goto|ifne|ifge|lookupswitch|if_icmpge)"); + map.put("returninstruction", "(lreturn|ireturn|freturn|dreturn|areturn|return)"); + map.put("storeinstruction", "(istore|fstore|dstore|astore|lstore)"); + map.put("select", "(tableswitch|lookupswitch)"); + map + .put( + "ifinstruction", + "(ifeq|ifgt|if_icmpne|if_icmpeq|ifge|ifnull|ifne|if_icmple|if_icmpge|if_acmpeq|if_icmplt|if_acmpne|ifnonnull|iflt|if_icmpgt|ifle)"); + map.put("jsrinstruction", "(jsr|jsr_w)"); + map.put("variablelengthinstruction", "(tableswitch|jsr|goto|lookupswitch)"); + map.put("unconditionalbranch", "(goto|jsr|jsr_w|athrow|goto_w)"); + map.put("constantpushinstruction", "(dconst|bipush|sipush|fconst|iconst|lconst)"); + map + .put( + "typedinstruction", + "(imul|lsub|aload|fload|lor|new|aaload|fcmpg|iand|iaload|lrem|idiv|d2l|isub|dcmpg|dastore|ret|f2d|f2i|drem|iinc|i2c|checkcast|frem|lreturn|astore|lushr|daload|dneg|fastore|istore|lshl|ldiv|lstore|areturn|ishr|ldc_w|invokeinterface|aastore|lxor|ishl|l2d|i2f|return|faload|sipush|iushr|caload|instanceof|invokespecial|putfield|fmul|ireturn|laload|d2f|lneg|ixor|i2l|fdiv|lastore|multianewarray|i2b|getstatic|i2d|putstatic|fcmpl|saload|ladd|irem|dload|jsr_w|dconst|dcmpl|fsub|freturn|ldc|aconst_null|castore|lmul|ldc2_w|dadd|iconst|f2l|ddiv|dstore|land|jsr|anewarray|dmul|bipush|dsub|sastore|d2i|i2s|lshr|iadd|l2i|lload|bastore|fstore|fneg|iload|fadd|baload|fconst|ior|ineg|dreturn|l2f|lconst|getfield|invokevirtual|invokestatic|iastore)"); + map.put("popinstruction", "(fstore|dstore|pop|pop2|astore|putstatic|istore|lstore)"); + map.put("allocationinstruction", "(multianewarray|new|anewarray|newarray)"); + map + .put( + "indexedinstruction", + "(lload|lstore|fload|ldc2_w|invokeinterface|multianewarray|astore|dload|putstatic|instanceof|getstatic|checkcast|getfield|invokespecial|dstore|istore|iinc|ldc_w|ret|fstore|invokestatic|iload|putfield|invokevirtual|ldc|new|aload|anewarray)"); + map + .put( + "pushinstruction", + "(dup|lload|dup2|bipush|fload|ldc2_w|sipush|lconst|fconst|dload|getstatic|ldc_w|aconst_null|dconst|iload|ldc|iconst|aload)"); + map + .put( + "stackproducer", + "(imul|lsub|aload|fload|lor|new|aaload|fcmpg|iand|iaload|lrem|idiv|d2l|isub|dcmpg|dup|f2d|f2i|drem|i2c|checkcast|frem|lushr|daload|dneg|lshl|ldiv|ishr|ldc_w|invokeinterface|lxor|ishl|l2d|i2f|faload|sipush|iushr|caload|instanceof|invokespecial|fmul|laload|d2f|lneg|ixor|i2l|fdiv|getstatic|i2b|swap|i2d|dup2|fcmpl|saload|ladd|irem|dload|jsr_w|dconst|dcmpl|fsub|ldc|arraylength|aconst_null|tableswitch|lmul|ldc2_w|iconst|dadd|f2l|ddiv|land|jsr|anewarray|dmul|bipush|dsub|d2i|newarray|i2s|lshr|iadd|lload|l2i|fneg|iload|fadd|baload|fconst|lookupswitch|ior|ineg|lconst|l2f|getfield|invokevirtual|invokestatic)"); + map + .put( + "stackconsumer", + "(imul|lsub|lor|iflt|fcmpg|if_icmpgt|iand|ifeq|if_icmplt|lrem|ifnonnull|idiv|d2l|isub|dcmpg|dastore|if_icmpeq|f2d|f2i|drem|i2c|checkcast|frem|lreturn|astore|lushr|pop2|monitorexit|dneg|fastore|istore|lshl|ldiv|lstore|areturn|if_icmpge|ishr|monitorenter|invokeinterface|aastore|lxor|ishl|l2d|i2f|return|iushr|instanceof|invokespecial|fmul|ireturn|d2f|lneg|ixor|pop|i2l|ifnull|fdiv|lastore|i2b|if_acmpeq|ifge|swap|i2d|putstatic|fcmpl|ladd|irem|dcmpl|fsub|freturn|ifgt|castore|lmul|dadd|f2l|ddiv|dstore|land|if_icmpne|if_acmpne|dmul|dsub|sastore|ifle|d2i|i2s|lshr|iadd|l2i|bastore|fstore|fneg|fadd|ior|ineg|ifne|dreturn|l2f|if_icmple|getfield|invokevirtual|invokestatic|iastore)"); + map + .put( + "exceptionthrower", + "(irem|lrem|laload|putstatic|baload|dastore|areturn|getstatic|ldiv|anewarray|iastore|castore|idiv|saload|lastore|fastore|putfield|lreturn|caload|getfield|return|aastore|freturn|newarray|instanceof|multianewarray|athrow|faload|iaload|aaload|dreturn|monitorenter|checkcast|bastore|arraylength|new|invokevirtual|sastore|ldc_w|ireturn|invokespecial|monitorexit|invokeinterface|ldc|invokestatic|daload)"); + map + .put( + "loadclass", + "(multianewarray|invokeinterface|instanceof|invokespecial|putfield|checkcast|putstatic|invokevirtual|new|getstatic|invokestatic|getfield|anewarray)"); + map + .put( + "instructiontargeter", + "(ifle|if_acmpne|if_icmpeq|if_acmpeq|ifnonnull|goto_w|iflt|ifnull|if_icmpne|tableswitch|if_icmple|ifeq|if_icmplt|jsr_w|if_icmpgt|ifgt|jsr|goto|ifne|ifge|lookupswitch|if_icmpge)"); + // Some aliases + map.put("if_icmp", "(if_icmpne|if_icmpeq|if_icmple|if_icmpge|if_icmplt|if_icmpgt)"); + map.put("if_acmp", "(if_acmpeq|if_acmpne)"); + map.put("if", "(ifeq|ifne|iflt|ifge|ifgt|ifle)"); + // Precompile some aliases first + map.put("iconst", precompile(Constants.ICONST_0, Constants.ICONST_5, Constants.ICONST_M1)); + map.put("lconst", new String(new char[] { + '(', makeChar(Constants.LCONST_0), '|', makeChar(Constants.LCONST_1), ')' + })); + map.put("dconst", new String(new char[] { + '(', makeChar(Constants.DCONST_0), '|', makeChar(Constants.DCONST_1), ')' + })); + map.put("fconst", new String(new char[] { + '(', makeChar(Constants.FCONST_0), '|', makeChar(Constants.FCONST_1), ')' + })); + map.put("iload", precompile(Constants.ILOAD_0, Constants.ILOAD_3, Constants.ILOAD)); + map.put("dload", precompile(Constants.DLOAD_0, Constants.DLOAD_3, Constants.DLOAD)); + map.put("fload", precompile(Constants.FLOAD_0, Constants.FLOAD_3, Constants.FLOAD)); + map.put("aload", precompile(Constants.ALOAD_0, Constants.ALOAD_3, Constants.ALOAD)); + map.put("istore", precompile(Constants.ISTORE_0, Constants.ISTORE_3, Constants.ISTORE)); + map.put("dstore", precompile(Constants.DSTORE_0, Constants.DSTORE_3, Constants.DSTORE)); + map.put("fstore", precompile(Constants.FSTORE_0, Constants.FSTORE_3, Constants.FSTORE)); + map.put("astore", precompile(Constants.ASTORE_0, Constants.ASTORE_3, Constants.ASTORE)); + // Compile strings + for (Iterator i = map.keySet().iterator(); i.hasNext();) { + String key = (String) i.next(); + String value = (String) map.get(key); + char ch = value.charAt(1); // Omit already precompiled patterns + if (ch < OFFSET) { + map.put(key, compilePattern(value)); // precompile all patterns + } + } + // Add instruction alias to match anything + StringBuffer buf = new StringBuffer("("); + for (short i = 0; i < NO_OPCODES; i++) { + if (Constants.NO_OF_OPERANDS[i] != Constants.UNDEFINED) { // Not an + // invalid + // opcode + buf.append(makeChar(i)); + if (i < NO_OPCODES - 1) { + buf.append('|'); + } + } + } + buf.append(')'); + map.put("instruction", buf.toString()); + } + + + private static String precompile( short from, short to, short extra ) { + StringBuffer buf = new StringBuffer("("); + for (short i = from; i <= to; i++) { + buf.append(makeChar(i)); + buf.append('|'); + } + buf.append(makeChar(extra)); + buf.append(")"); + return buf.toString(); + } + + + /* + * Internal debugging routines. + */ + private static final String pattern2string( String pattern ) { + return pattern2string(pattern, true); + } + + + private static final String pattern2string( String pattern, boolean make_string ) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < pattern.length(); i++) { + char ch = pattern.charAt(i); + if (ch >= OFFSET) { + if (make_string) { + buf.append(Constants.OPCODE_NAMES[ch - OFFSET]); + } else { + buf.append((ch - OFFSET)); + } + } else { + buf.append(ch); + } + } + return buf.toString(); + } +} diff --git a/src/org/apache/bcel/util/JavaWrapper.java b/src/org/apache/bcel/util/JavaWrapper.java new file mode 100644 index 0000000..fb36b07 --- /dev/null +++ b/src/org/apache/bcel/util/JavaWrapper.java @@ -0,0 +1,117 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Java interpreter replacement, i.e., wrapper that uses its own ClassLoader + * to modify/generate classes as they're requested. You can take this as a template + * for your own applications.
      + * Call this wrapper with + *

      java org.apache.bcel.util.JavaWrapper <real.class.name> [arguments]
      + *

      + * To use your own class loader you can set the "bcel.classloader" system property + * which defaults to "org.apache.bcel.util.ClassLoader", e.g., with + *

      java org.apache.bcel.util.JavaWrapper -Dbcel.classloader=foo.MyLoader <real.class.name> [arguments]
      + *

      + * + * @version $Id: JavaWrapper.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @see ClassLoader + */ +public class JavaWrapper { + + private java.lang.ClassLoader loader; + + + private static java.lang.ClassLoader getClassLoader() { + String s = System.getProperty("bcel.classloader"); + if ((s == null) || "".equals(s)) { + s = "org.apache.bcel.util.ClassLoader"; + } + try { + return (java.lang.ClassLoader) Class.forName(s).newInstance(); + } catch (Exception e) { + throw new RuntimeException(e.toString()); + } + } + + + public JavaWrapper(java.lang.ClassLoader loader) { + this.loader = loader; + } + + + public JavaWrapper() { + this(getClassLoader()); + } + + + /** Runs the main method of the given class with the arguments passed in argv + * + * @param class_name the fully qualified class name + * @param argv the arguments just as you would pass them directly + */ + public void runMain( String class_name, String[] argv ) throws ClassNotFoundException { + Class cl = loader.loadClass(class_name); + Method method = null; + try { + method = cl.getMethod("main", new Class[] { + argv.getClass() + }); + /* Method main is sane ? + */ + int m = method.getModifiers(); + Class r = method.getReturnType(); + if (!(Modifier.isPublic(m) && Modifier.isStatic(m)) || Modifier.isAbstract(m) + || (r != Void.TYPE)) { + throw new NoSuchMethodException(); + } + } catch (NoSuchMethodException no) { + System.out.println("In class " + class_name + + ": public static void main(String[] argv) is not defined"); + return; + } + try { + method.invoke(null, new Object[] { + argv + }); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + + /** Default main method used as wrapper, expects the fully qualified class name + * of the real class as the first argument. + */ + public static void main( String[] argv ) throws Exception { + /* Expects class name as first argument, other arguments are by-passed. + */ + if (argv.length == 0) { + System.out.println("Missing class name."); + return; + } + String class_name = argv[0]; + String[] new_argv = new String[argv.length - 1]; + System.arraycopy(argv, 1, new_argv, 0, new_argv.length); + JavaWrapper wrapper = new JavaWrapper(); + wrapper.runMain(class_name, new_argv); + } +} diff --git a/src/org/apache/bcel/util/MethodHTML.java b/src/org/apache/bcel/util/MethodHTML.java new file mode 100644 index 0000000..efaa6a1 --- /dev/null +++ b/src/org/apache/bcel/util/MethodHTML.java @@ -0,0 +1,156 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import org.apache.bcel.classfile.Attribute; +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.ConstantValue; +import org.apache.bcel.classfile.ExceptionTable; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.Utility; + +/** + * Convert methods and fields into HTML file. + * + * @version $Id: MethodHTML.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * + */ +final class MethodHTML implements org.apache.bcel.Constants { + + private String class_name; // name of current class + private PrintWriter file; // file to write to + private ConstantHTML constant_html; + private AttributeHTML attribute_html; + + + MethodHTML(String dir, String class_name, Method[] methods, Field[] fields, + ConstantHTML constant_html, AttributeHTML attribute_html) throws IOException { + this.class_name = class_name; + this.attribute_html = attribute_html; + this.constant_html = constant_html; + file = new PrintWriter(new FileOutputStream(dir + class_name + "_methods.html")); + file.println(""); + file.println("" + + ""); + for (int i = 0; i < fields.length; i++) { + writeField(fields[i]); + } + file.println("
      Access flagsTypeField name
      "); + file.println("" + + "" + + ""); + for (int i = 0; i < methods.length; i++) { + writeMethod(methods[i], i); + } + file.println("
      Access flagsReturn typeMethod nameArguments
      "); + file.close(); + } + + + /** + * Print field of class. + * + * @param field field to print + * @exception java.io.IOException + */ + private void writeField( Field field ) throws IOException { + String type = Utility.signatureToString(field.getSignature()); + String name = field.getName(); + String access = Utility.accessToString(field.getAccessFlags()); + Attribute[] attributes; + access = Utility.replace(access, " ", " "); + file.print("" + access + "\n" + + Class2HTML.referenceType(type) + "" + name + + ""); + attributes = field.getAttributes(); + // Write them to the Attributes.html file with anchor "[]" + for (int i = 0; i < attributes.length; i++) { + attribute_html.writeAttribute(attributes[i], name + "@" + i); + } + for (int i = 0; i < attributes.length; i++) { + if (attributes[i].getTag() == ATTR_CONSTANT_VALUE) { // Default value + String str = ((ConstantValue) attributes[i]).toString(); + // Reference attribute in _attributes.html + file.print("= " + str + "\n"); + break; + } + } + file.println(""); + } + + + private final void writeMethod( Method method, int method_number ) throws IOException { + // Get raw signature + String signature = method.getSignature(); + // Get array of strings containing the argument types + String[] args = Utility.methodSignatureArgumentTypes(signature, false); + // Get return type string + String type = Utility.methodSignatureReturnType(signature, false); + // Get method name + String name = method.getName(), html_name; + // Get method's access flags + String access = Utility.accessToString(method.getAccessFlags()); + // Get the method's attributes, the Code Attribute in particular + Attribute[] attributes = method.getAttributes(); + /* HTML doesn't like names like and spaces are places to break + * lines. Both we don't want... + */ + access = Utility.replace(access, " ", " "); + html_name = Class2HTML.toHTML(name); + file.print("" + access + ""); + file.print("" + Class2HTML.referenceType(type) + "" + "" + html_name + + "\n("); + for (int i = 0; i < args.length; i++) { + file.print(Class2HTML.referenceType(args[i])); + if (i < args.length - 1) { + file.print(", "); + } + } + file.print(")"); + // Check for thrown exceptions + for (int i = 0; i < attributes.length; i++) { + attribute_html.writeAttribute(attributes[i], "method" + method_number + "@" + i, + method_number); + byte tag = attributes[i].getTag(); + if (tag == ATTR_EXCEPTIONS) { + file.print("throws"); + int[] exceptions = ((ExceptionTable) attributes[i]).getExceptionIndexTable(); + for (int j = 0; j < exceptions.length; j++) { + file.print(constant_html.referenceConstant(exceptions[j])); + if (j < exceptions.length - 1) { + file.print(", "); + } + } + file.println(""); + } else if (tag == ATTR_CODE) { + Attribute[] c_a = ((Code) attributes[i]).getAttributes(); + for (int j = 0; j < c_a.length; j++) { + attribute_html.writeAttribute(c_a[j], "method" + method_number + "@" + i + "@" + + j, method_number); + } + } + } + } +} diff --git a/src/org/apache/bcel/util/Repository.java b/src/org/apache/bcel/util/Repository.java new file mode 100644 index 0000000..868cf07 --- /dev/null +++ b/src/org/apache/bcel/util/Repository.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import org.apache.bcel.classfile.JavaClass; + +/** + * Abstract definition of a class repository. Instances may be used + * to load classes from different sources and may be used in the + * Repository.setRepository method. + * + * @see org.apache.bcel.Repository + * @version $Id: Repository.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @author David Dixon-Peugh + */ +public interface Repository extends java.io.Serializable { + + /** + * Store the provided class under "clazz.getClassName()" + */ + public void storeClass( JavaClass clazz ); + + + /** + * Remove class from repository + */ + public void removeClass( JavaClass clazz ); + + + /** + * Find the class with the name provided, if the class + * isn't there, return NULL. + */ + public JavaClass findClass( String className ); + + + /** + * Find the class with the name provided, if the class + * isn't there, make an attempt to load it. + */ + public JavaClass loadClass( String className ) throws java.lang.ClassNotFoundException; + + + /** + * Find the JavaClass instance for the given run-time class object + */ + public JavaClass loadClass( Class clazz ) throws java.lang.ClassNotFoundException; + + + /** Clear all entries from cache. + */ + public void clear(); + + + /** Get the ClassPath associated with this Repository + */ + public ClassPath getClassPath(); +} diff --git a/src/org/apache/bcel/util/SyntheticRepository.java b/src/org/apache/bcel/util/SyntheticRepository.java new file mode 100644 index 0000000..65b2a51 --- /dev/null +++ b/src/org/apache/bcel/util/SyntheticRepository.java @@ -0,0 +1,190 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.util; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.Map; +import org.apache.bcel.classfile.ClassParser; +import org.apache.bcel.classfile.JavaClass; + +/** + * This repository is used in situations where a Class is created + * outside the realm of a ClassLoader. Classes are loaded from + * the file systems using the paths specified in the given + * class path. By default, this is the value returned by + * ClassPath.getClassPath(). + *
      + * It is designed to be used as a singleton, however it + * can also be used with custom classpaths. + * + /** + * Abstract definition of a class repository. Instances may be used + * to load classes from different sources and may be used in the + * Repository.setRepository method. + * + * @see org.apache.bcel.Repository + * + * @version $Id: SyntheticRepository.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author M. Dahm + * @author David Dixon-Peugh + */ +public class SyntheticRepository implements Repository { + + private static final String DEFAULT_PATH = ClassPath.getClassPath(); + private static Map _instances = new HashMap(); // CLASSPATH X REPOSITORY + private ClassPath _path = null; + private Map _loadedClasses = new HashMap(); // CLASSNAME X JAVACLASS + + + private SyntheticRepository(ClassPath path) { + _path = path; + } + + + public static SyntheticRepository getInstance() { + return getInstance(ClassPath.SYSTEM_CLASS_PATH); + } + + + public static SyntheticRepository getInstance( ClassPath classPath ) { + SyntheticRepository rep = (SyntheticRepository) _instances.get(classPath); + if (rep == null) { + rep = new SyntheticRepository(classPath); + _instances.put(classPath, rep); + } + return rep; + } + + + /** + * Store a new JavaClass instance into this Repository. + */ + public void storeClass( JavaClass clazz ) { + _loadedClasses.put(clazz.getClassName(), new SoftReference(clazz)); + clazz.setRepository(this); + } + + + /** + * Remove class from repository + */ + public void removeClass( JavaClass clazz ) { + _loadedClasses.remove(clazz.getClassName()); + } + + + /** + * Find an already defined (cached) JavaClass object by name. + */ + public JavaClass findClass( String className ) { + SoftReference ref = (SoftReference) _loadedClasses.get(className); + if (ref == null) { + return null; + } + return (JavaClass) ref.get(); + } + + + /** + * Find a JavaClass object by name. + * If it is already in this Repository, the Repository version + * is returned. Otherwise, the Repository's classpath is searched for + * the class (and it is added to the Repository if found). + * + * @param className the name of the class + * @return the JavaClass object + * @throws ClassNotFoundException if the class is not in the + * Repository, and could not be found on the classpath + */ + public JavaClass loadClass( String className ) throws ClassNotFoundException { + if (className == null || className.equals("")) { + throw new IllegalArgumentException("Invalid class name " + className); + } + className = className.replace('/', '.'); // Just in case, canonical form + JavaClass clazz = findClass(className); + if (clazz != null) { + return clazz; + } + try { + return loadClass(_path.getInputStream(className), className); + } catch (IOException e) { + throw new ClassNotFoundException("Exception while looking for class " + className + + ": " + e.toString()); + } + } + + + /** + * Find the JavaClass object for a runtime Class object. + * If a class with the same name is already in this Repository, + * the Repository version is returned. Otherwise, getResourceAsStream() + * is called on the Class object to find the class's representation. + * If the representation is found, it is added to the Repository. + * + * @see Class + * @param clazz the runtime Class object + * @return JavaClass object for given runtime class + * @throws ClassNotFoundException if the class is not in the + * Repository, and its representation could not be found + */ + public JavaClass loadClass( Class clazz ) throws ClassNotFoundException { + String className = clazz.getName(); + JavaClass repositoryClass = findClass(className); + if (repositoryClass != null) { + return repositoryClass; + } + String name = className; + int i = name.lastIndexOf('.'); + if (i > 0) { + name = name.substring(i + 1); + } + return loadClass(clazz.getResourceAsStream(name + ".class"), className); + } + + + private JavaClass loadClass( InputStream is, String className ) throws ClassNotFoundException { + try { + if (is != null) { + ClassParser parser = new ClassParser(is, className); + JavaClass clazz = parser.parse(); + storeClass(clazz); + return clazz; + } + } catch (IOException e) { + throw new ClassNotFoundException("Exception while looking for class " + className + + ": " + e.toString()); + } + throw new ClassNotFoundException("SyntheticRepository could not load " + className); + } + + + /** ClassPath associated with the Repository. + */ + public ClassPath getClassPath() { + return _path; + } + + + /** Clear all entries from cache. + */ + public void clear() { + _loadedClasses.clear(); + } +} diff --git a/src/org/apache/bcel/util/package.html b/src/org/apache/bcel/util/package.html new file mode 100644 index 0000000..a58b20f --- /dev/null +++ b/src/org/apache/bcel/util/package.html @@ -0,0 +1,25 @@ + + + + + + +

      +This package contains utility classes for the +Byte Code Engineering +Library, namely: +

      +

      +

        +
      • Collection classes for JavaClass objects
      • +
      • A converter for class files to HTML
      • +
      • A tool to find instructions patterns via regular expressions
      • +
      • A class to find classes as defined in the CLASSPATH
      • +
      • A class loader that allows to create classes at run time
      • +
      + +

      + + diff --git a/src/org/apache/bcel/verifier/GraphicalVerifier.java b/src/org/apache/bcel/verifier/GraphicalVerifier.java new file mode 100644 index 0000000..dceaeba --- /dev/null +++ b/src/org/apache/bcel/verifier/GraphicalVerifier.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +import java.awt.Dimension; +import java.awt.Toolkit; +import javax.swing.UIManager; +import org.apache.bcel.generic.Type; + +/** + * A graphical user interface application demonstrating JustIce. + * + * @version $Id: GraphicalVerifier.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public class GraphicalVerifier { + + boolean packFrame = false; + + + /** Constructor. */ + public GraphicalVerifier() { + VerifierAppFrame frame = new VerifierAppFrame(); + if (packFrame) { + frame.pack(); + } else { + frame.validate(); + } + //Das Fenster zentrieren + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension frameSize = frame.getSize(); + if (frameSize.height > screenSize.height) { + frameSize.height = screenSize.height; + } + if (frameSize.width > screenSize.width) { + frameSize.width = screenSize.width; + } + frame.setLocation((screenSize.width - frameSize.width) / 2, + (screenSize.height - frameSize.height) / 2); + frame.setVisible(true); + frame.classNamesJList.setModel(new VerifierFactoryListModel()); + VerifierFactory.getVerifier(Type.OBJECT.getClassName()); // Fill list with java.lang.Object + frame.classNamesJList.setSelectedIndex(0); // default, will verify java.lang.Object + } + + + /** Main method. */ + public static void main( String[] args ) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + e.printStackTrace(); + } + new GraphicalVerifier(); + } +} diff --git a/src/org/apache/bcel/verifier/NativeVerifier.java b/src/org/apache/bcel/verifier/NativeVerifier.java new file mode 100644 index 0000000..9870656 --- /dev/null +++ b/src/org/apache/bcel/verifier/NativeVerifier.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +/** + * The NativeVerifier class implements a main(String[] args) method that's + * roughly compatible to the one in the Verifier class, but that uses the + * JVM's internal verifier for its class file verification. + * This can be used for comparison runs between the JVM-internal verifier + * and JustIce. + * + * @version $Id: NativeVerifier.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public abstract class NativeVerifier { + + /** + * This class must not be instantiated. + */ + private NativeVerifier() { + } + + + /** + * Works only on the first argument. + */ + public static void main( String[] args ) { + if (args.length != 1) { + System.out.println("Verifier front-end: need exactly one argument."); + System.exit(1); + } + int dotclasspos = args[0].lastIndexOf(".class"); + if (dotclasspos != -1) { + args[0] = args[0].substring(0, dotclasspos); + } + args[0] = args[0].replace('/', '.'); + //System.out.println(args[0]); + try { + Class.forName(args[0]); + } catch (ExceptionInInitializerError eiie) { //subclass of LinkageError! + System.out.println("NativeVerifier: ExceptionInInitializerError encountered on '" + + args[0] + "'."); + System.out.println(eiie); + System.exit(1); + } catch (LinkageError le) { + System.out.println("NativeVerifier: LinkageError encountered on '" + args[0] + "'."); + System.out.println(le); + System.exit(1); + } catch (ClassNotFoundException cnfe) { + System.out.println("NativeVerifier: FILE NOT FOUND: '" + args[0] + "'."); + System.exit(1); + } catch (Throwable t) { + System.out.println("NativeVerifier: Unspecified verification error on'" + args[0] + + "'."); + System.exit(1); + } + System.out.println("NativeVerifier: Class file '" + args[0] + "' seems to be okay."); + System.exit(0); + } +} diff --git a/src/org/apache/bcel/verifier/PassVerifier.java b/src/org/apache/bcel/verifier/PassVerifier.java new file mode 100644 index 0000000..b47e5fc --- /dev/null +++ b/src/org/apache/bcel/verifier/PassVerifier.java @@ -0,0 +1,105 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +import java.util.ArrayList; +import java.util.List; + +/** + * A PassVerifier actually verifies a class file; it is instantiated + * by a Verifier. + * The verification should conform with a certain pass as described + * in The Java Virtual Machine Specification, 2nd edition. + * This book describes four passes. Pass one means loading the + * class and verifying a few static constraints. Pass two actually + * verifies some other constraints that could enforce loading in + * referenced class files. Pass three is the first pass that actually + * checks constraints in the code array of a method in the class file; + * it has two parts with the first verifying static constraints and + * the second part verifying structural constraints (where a data flow + * analysis is used for). The fourth pass, finally, performs checks + * that can only be done at run-time. + * JustIce does not have a run-time pass, but certain constraints that + * are usually delayed until run-time for performance reasons are also + * checked during the second part of pass three. + * PassVerifier instances perform caching. + * That means, if you really want a new verification run of a certain + * pass you must use a new instance of a given PassVerifier. + * + * @version $Id: PassVerifier.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + * @see org.apache.bcel.verifier.Verifier + * @see #verify() + */ +public abstract class PassVerifier { + + /** The (warning) messages. */ + private List messages = new ArrayList(); //Type of elements: String + /** The VerificationResult cache. */ + private VerificationResult verificationResult = null; + + + /** + * This method runs a verification pass conforming to the + * Java Virtual Machine Specification, 2nd edition, on a + * class file. + * PassVerifier instances perform caching; + * i.e. if the verify() method once determined a VerificationResult, + * then this result may be returned after every invocation of this + * method instead of running the verification pass anew; likewise with + * the result of getMessages(). + * + * @see #getMessages() + * @see #addMessage(String) + */ + public VerificationResult verify() { + if (verificationResult == null) { + verificationResult = do_verify(); + } + return verificationResult; + } + + + /** Does the real verification work, uncached. */ + public abstract VerificationResult do_verify(); + + + /** + * This method adds a (warning) message to the message pool of this + * PassVerifier. This method is normally only internally used by + * BCEL's class file verifier "JustIce" and should not be used from + * the outside. + * + * @see #getMessages() + */ + public void addMessage( String message ) { + messages.add(message); + } + + + /** + * Returns the (warning) messages that this PassVerifier accumulated + * during its do_verify()ing work. + * + * @see #addMessage(String) + * @see #do_verify() + */ + public String[] getMessages() { + verify(); // create messages if not already done (cached!) + return (String[]) messages.toArray(new String[messages.size()]); + } +} diff --git a/src/org/apache/bcel/verifier/TransitiveHull.java b/src/org/apache/bcel/verifier/TransitiveHull.java new file mode 100644 index 0000000..db11cc2 --- /dev/null +++ b/src/org/apache/bcel/verifier/TransitiveHull.java @@ -0,0 +1,104 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.JavaClass; + +/** + * This class has a main method implementing a demonstration program + * of how to use the VerifierFactoryObserver. It transitively verifies + * all class files encountered; this may take up a lot of time and, + * more notably, memory. + * + * @version $Id: TransitiveHull.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public class TransitiveHull implements VerifierFactoryObserver { + + /** Used for indentation. */ + private int indent = 0; + + + /** Not publicly instantiable. */ + private TransitiveHull() { + } + + + /* Implementing VerifierFactoryObserver. */ + public void update( String classname ) { + System.gc(); // avoid swapping if possible. + for (int i = 0; i < indent; i++) { + System.out.print(" "); + } + System.out.println(classname); + indent += 1; + Verifier v = VerifierFactory.getVerifier(classname); + VerificationResult vr; + vr = v.doPass1(); + if (vr != VerificationResult.VR_OK) { + System.out.println("Pass 1:\n" + vr); + } + vr = v.doPass2(); + if (vr != VerificationResult.VR_OK) { + System.out.println("Pass 2:\n" + vr); + } + if (vr == VerificationResult.VR_OK) { + try { + JavaClass jc = Repository.lookupClass(v.getClassName()); + for (int i = 0; i < jc.getMethods().length; i++) { + vr = v.doPass3a(i); + if (vr != VerificationResult.VR_OK) { + System.out.println(v.getClassName() + ", Pass 3a, method " + i + " ['" + + jc.getMethods()[i] + "']:\n" + vr); + } + vr = v.doPass3b(i); + if (vr != VerificationResult.VR_OK) { + System.out.println(v.getClassName() + ", Pass 3b, method " + i + " ['" + + jc.getMethods()[i] + "']:\n" + vr); + } + } + } catch (ClassNotFoundException e) { + System.err.println("Could not find class " + v.getClassName() + " in Repository"); + } + } + indent -= 1; + } + + + /** + * This method implements a demonstration program + * of how to use the VerifierFactoryObserver. It transitively verifies + * all class files encountered; this may take up a lot of time and, + * more notably, memory. + */ + public static void main( String[] args ) { + if (args.length != 1) { + System.out.println("Need exactly one argument: The root class to verify."); + System.exit(1); + } + int dotclasspos = args[0].lastIndexOf(".class"); + if (dotclasspos != -1) { + args[0] = args[0].substring(0, dotclasspos); + } + args[0] = args[0].replace('/', '.'); + TransitiveHull th = new TransitiveHull(); + VerifierFactory.attach(th); + VerifierFactory.getVerifier(args[0]); // the observer is called back and does the actual trick. + VerifierFactory.detach(th); + } +} diff --git a/src/org/apache/bcel/verifier/VerificationResult.java b/src/org/apache/bcel/verifier/VerificationResult.java new file mode 100644 index 0000000..0643a44 --- /dev/null +++ b/src/org/apache/bcel/verifier/VerificationResult.java @@ -0,0 +1,115 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +/** + * A VerificationResult is what a PassVerifier returns + * after verifying. + * + * @version $Id: VerificationResult.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + * + */ +public class VerificationResult { + + /** + * Constant to indicate verification has not been tried yet. + * This happens if some earlier verification pass did not return VERIFIED_OK. + */ + public static final int VERIFIED_NOTYET = 0; + /** Constant to indicate verification was passed. */ + public static final int VERIFIED_OK = 1; + /** Constant to indicate verfication failed. */ + public static final int VERIFIED_REJECTED = 2; + /** + * This string is the canonical message for verifications that have not been tried yet. + * This happens if some earlier verification pass did not return VERIFIED_OK. + */ + private static final String VERIFIED_NOTYET_MSG = "Not yet verified."; + /** This string is the canonical message for passed verification passes. */ + private static final String VERIFIED_OK_MSG = "Passed verification."; + /** + * Canonical VerificationResult for not-yet-tried verifications. + * This happens if some earlier verification pass did not return VERIFIED_OK. + */ + public static final VerificationResult VR_NOTYET = new VerificationResult(VERIFIED_NOTYET, + VERIFIED_NOTYET_MSG); + /** Canonical VerificationResult for passed verifications. */ + public static final VerificationResult VR_OK = new VerificationResult(VERIFIED_OK, + VERIFIED_OK_MSG); + /** The numeric status. */ + private int numeric; + /** The detailed message. */ + private String detailMessage; + + + /** The usual constructor. */ + public VerificationResult(int status, String message) { + numeric = status; + detailMessage = message; + } + + + /** Returns one one the VERIFIED_OK, VERIFIED_NOTYET, VERIFIED_REJECTED constants. */ + public int getStatus() { + return numeric; + } + + + /** Returns a detailed message. */ + public String getMessage() { + return detailMessage; + } + + + /** @return a hash code value for the object. + */ + public int hashCode() { + return numeric ^ detailMessage.hashCode(); + } + + + /** + * Returns if two VerificationResult instances are equal. + */ + public boolean equals( Object o ) { + if (!(o instanceof VerificationResult)) { + return false; + } + VerificationResult other = (VerificationResult) o; + return ((other.numeric == this.numeric) && (other.detailMessage.equals(this.detailMessage))); + } + + + /** + * Returns a String representation of the VerificationResult. + */ + public String toString() { + String ret = ""; + if (numeric == VERIFIED_NOTYET) { + ret = "VERIFIED_NOTYET"; + } + if (numeric == VERIFIED_OK) { + ret = "VERIFIED_OK"; + } + if (numeric == VERIFIED_REJECTED) { + ret = "VERIFIED_REJECTED"; + } + ret += "\n" + detailMessage + "\n"; + return ret; + } +} diff --git a/src/org/apache/bcel/verifier/Verifier.java b/src/org/apache/bcel/verifier/Verifier.java new file mode 100644 index 0000000..89b2ef8 --- /dev/null +++ b/src/org/apache/bcel/verifier/Verifier.java @@ -0,0 +1,248 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.verifier.statics.Pass1Verifier; +import org.apache.bcel.verifier.statics.Pass2Verifier; +import org.apache.bcel.verifier.statics.Pass3aVerifier; +import org.apache.bcel.verifier.structurals.Pass3bVerifier; + +/** + * A Verifier instance is there to verify a class file according to The Java Virtual + * Machine Specification, 2nd Edition. + * + * Pass-3b-verification includes pass-3a-verification; + * pass-3a-verification includes pass-2-verification; + * pass-2-verification includes pass-1-verification. + * + * A Verifier creates PassVerifier instances to perform the actual verification. + * Verifier instances are usually generated by the VerifierFactory. + * + * @version $Id: Verifier.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + * @see org.apache.bcel.verifier.VerifierFactory + * @see org.apache.bcel.verifier.PassVerifier + */ +public class Verifier { + + /** + * The name of the class this verifier operates on. + */ + private final String classname; + /** A Pass1Verifier for this Verifier instance. */ + private Pass1Verifier p1v; + /** A Pass2Verifier for this Verifier instance. */ + private Pass2Verifier p2v; + /** The Pass3aVerifiers for this Verifier instance. Key: Interned string specifying the method number. */ + private Map p3avs = new HashMap(); + /** The Pass3bVerifiers for this Verifier instance. Key: Interned string specifying the method number. */ + private Map p3bvs = new HashMap(); + + + /** Returns the VerificationResult for the given pass. */ + public VerificationResult doPass1() { + if (p1v == null) { + p1v = new Pass1Verifier(this); + } + return p1v.verify(); + } + + + /** Returns the VerificationResult for the given pass. */ + public VerificationResult doPass2() { + if (p2v == null) { + p2v = new Pass2Verifier(this); + } + return p2v.verify(); + } + + + /** Returns the VerificationResult for the given pass. */ + public VerificationResult doPass3a( int method_no ) { + String key = Integer.toString(method_no); + Pass3aVerifier p3av; + p3av = (Pass3aVerifier) (p3avs.get(key)); + if (p3avs.get(key) == null) { + p3av = new Pass3aVerifier(this, method_no); + p3avs.put(key, p3av); + } + return p3av.verify(); + } + + + /** Returns the VerificationResult for the given pass. */ + public VerificationResult doPass3b( int method_no ) { + String key = Integer.toString(method_no); + Pass3bVerifier p3bv; + p3bv = (Pass3bVerifier) (p3bvs.get(key)); + if (p3bvs.get(key) == null) { + p3bv = new Pass3bVerifier(this, method_no); + p3bvs.put(key, p3bv); + } + return p3bv.verify(); + } + + + /** + * Instantiation is done by the VerifierFactory. + * + * @see VerifierFactory + */ + Verifier(String fully_qualified_classname) { + classname = fully_qualified_classname; + flush(); + } + + + /** + * Returns the name of the class this verifier operates on. + * This is particularly interesting when this verifier was created + * recursively by another Verifier and you got a reference to this + * Verifier by the getVerifiers() method of the VerifierFactory. + * @see VerifierFactory + */ + public final String getClassName() { + return classname; + } + + + /** + * Forget everything known about the class file; that means, really + * start a new verification of a possibly different class file from + * BCEL's repository. + * + */ + public void flush() { + p1v = null; + p2v = null; + p3avs.clear(); + p3bvs.clear(); + } + + + /** + * This returns all the (warning) messages collected during verification. + * A prefix shows from which verifying pass a message originates. + */ + public String[] getMessages() throws ClassNotFoundException { + ArrayList messages = new ArrayList(); + if (p1v != null) { + String[] p1m = p1v.getMessages(); + for (int i = 0; i < p1m.length; i++) { + messages.add("Pass 1: " + p1m[i]); + } + } + if (p2v != null) { + String[] p2m = p2v.getMessages(); + for (int i = 0; i < p2m.length; i++) { + messages.add("Pass 2: " + p2m[i]); + } + } + Iterator p3as = p3avs.values().iterator(); + while (p3as.hasNext()) { + Pass3aVerifier pv = (Pass3aVerifier) p3as.next(); + String[] p3am = pv.getMessages(); + int meth = pv.getMethodNo(); + for (int i = 0; i < p3am.length; i++) { + messages.add("Pass 3a, method " + meth + " ('" + + org.apache.bcel.Repository.lookupClass(classname).getMethods()[meth] + + "'): " + p3am[i]); + } + } + Iterator p3bs = p3bvs.values().iterator(); + while (p3bs.hasNext()) { + Pass3bVerifier pv = (Pass3bVerifier) p3bs.next(); + String[] p3bm = pv.getMessages(); + int meth = pv.getMethodNo(); + for (int i = 0; i < p3bm.length; i++) { + messages.add("Pass 3b, method " + meth + " ('" + + org.apache.bcel.Repository.lookupClass(classname).getMethods()[meth] + + "'): " + p3bm[i]); + } + } + String[] ret = new String[messages.size()]; + for (int i = 0; i < messages.size(); i++) { + ret[i] = (String) messages.get(i); + } + return ret; + } + + + /** + * Verifies class files. + * This is a simple demonstration of how the API of BCEL's + * class file verifier "JustIce" may be used. + * You should supply command-line arguments which are + * fully qualified namea of the classes to verify. These class files + * must be somewhere in your CLASSPATH (refer to Sun's + * documentation for questions about this) or you must have put the classes + * into the BCEL Repository yourself (via 'addClass(JavaClass)'). + */ + public static void main( String[] args ) { + System.out + .println("JustIce by Enver Haase, (C) 2001-2002.\n\n\n"); + for (int k = 0; k < args.length; k++) { + try { + if (args[k].endsWith(".class")) { + int dotclasspos = args[k].lastIndexOf(".class"); + if (dotclasspos != -1) { + args[k] = args[k].substring(0, dotclasspos); + } + } + args[k] = args[k].replace('/', '.'); + System.out.println("Now verifying: " + args[k] + "\n"); + Verifier v = VerifierFactory.getVerifier(args[k]); + VerificationResult vr; + vr = v.doPass1(); + System.out.println("Pass 1:\n" + vr); + vr = v.doPass2(); + System.out.println("Pass 2:\n" + vr); + if (vr == VerificationResult.VR_OK) { + JavaClass jc = org.apache.bcel.Repository.lookupClass(args[k]); + for (int i = 0; i < jc.getMethods().length; i++) { + vr = v.doPass3a(i); + System.out.println("Pass 3a, method number " + i + " ['" + + jc.getMethods()[i] + "']:\n" + vr); + vr = v.doPass3b(i); + System.out.println("Pass 3b, method number " + i + " ['" + + jc.getMethods()[i] + "']:\n" + vr); + } + } + System.out.println("Warnings:"); + String[] warnings = v.getMessages(); + if (warnings.length == 0) { + System.out.println(""); + } + for (int j = 0; j < warnings.length; j++) { + System.out.println(warnings[j]); + } + System.out.println("\n"); + // avoid swapping. + v.flush(); + org.apache.bcel.Repository.clearCache(); + System.gc(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/org/apache/bcel/verifier/VerifierAppFrame.java b/src/org/apache/bcel/verifier/VerifierAppFrame.java new file mode 100644 index 0000000..b9bd55c --- /dev/null +++ b/src/org/apache/bcel/verifier/VerifierAppFrame.java @@ -0,0 +1,396 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +import java.awt.AWTEvent; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.WindowEvent; +import javax.swing.BorderFactory; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTextPane; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.JavaClass; + +/** + * This class implements a machine-generated frame for use with + * the GraphicalVerfifier. + * + * @version $Id: VerifierAppFrame.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + * @see GraphicalVerifier + */ +public class VerifierAppFrame extends JFrame { + + JPanel contentPane; + JSplitPane jSplitPane1 = new JSplitPane(); + JPanel jPanel1 = new JPanel(); + JPanel jPanel2 = new JPanel(); + JSplitPane jSplitPane2 = new JSplitPane(); + JPanel jPanel3 = new JPanel(); + JList classNamesJList = new JList(); + GridLayout gridLayout1 = new GridLayout(); + JPanel messagesPanel = new JPanel(); + GridLayout gridLayout2 = new GridLayout(); + JMenuBar jMenuBar1 = new JMenuBar(); + JMenu jMenu1 = new JMenu(); + JScrollPane jScrollPane1 = new JScrollPane(); + JScrollPane messagesScrollPane = new JScrollPane(); + JScrollPane jScrollPane3 = new JScrollPane(); + GridLayout gridLayout4 = new GridLayout(); + JScrollPane jScrollPane4 = new JScrollPane(); + CardLayout cardLayout1 = new CardLayout(); + private String JUSTICE_VERSION = "JustIce by Enver Haase"; + private String current_class; + GridLayout gridLayout3 = new GridLayout(); + JTextPane pass1TextPane = new JTextPane(); + JTextPane pass2TextPane = new JTextPane(); + JTextPane messagesTextPane = new JTextPane(); + JMenuItem newFileMenuItem = new JMenuItem(); + JSplitPane jSplitPane3 = new JSplitPane(); + JSplitPane jSplitPane4 = new JSplitPane(); + JScrollPane jScrollPane2 = new JScrollPane(); + JScrollPane jScrollPane5 = new JScrollPane(); + JScrollPane jScrollPane6 = new JScrollPane(); + JScrollPane jScrollPane7 = new JScrollPane(); + JList pass3aJList = new JList(); + JList pass3bJList = new JList(); + JTextPane pass3aTextPane = new JTextPane(); + JTextPane pass3bTextPane = new JTextPane(); + JMenu jMenu2 = new JMenu(); + JMenuItem whatisMenuItem = new JMenuItem(); + JMenuItem aboutMenuItem = new JMenuItem(); + + + /** Constructor. */ + public VerifierAppFrame() { + enableEvents(AWTEvent.WINDOW_EVENT_MASK); + try { + jbInit(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + /** Initizalization of the components. */ + private void jbInit() throws Exception { + //setIconImage(Toolkit.getDefaultToolkit().createImage(Frame1.class.getResource("[Ihr Symbol]"))); + contentPane = (JPanel) this.getContentPane(); + contentPane.setLayout(cardLayout1); + this.setJMenuBar(jMenuBar1); + this.setSize(new Dimension(708, 451)); + this.setTitle("JustIce"); + jPanel1.setMinimumSize(new Dimension(100, 100)); + jPanel1.setPreferredSize(new Dimension(100, 100)); + jPanel1.setLayout(gridLayout1); + jSplitPane2.setOrientation(JSplitPane.VERTICAL_SPLIT); + jPanel2.setLayout(gridLayout2); + jPanel3.setMinimumSize(new Dimension(200, 100)); + jPanel3.setPreferredSize(new Dimension(400, 400)); + jPanel3.setLayout(gridLayout4); + messagesPanel.setMinimumSize(new Dimension(100, 100)); + messagesPanel.setLayout(gridLayout3); + jPanel2.setMinimumSize(new Dimension(200, 100)); + jMenu1.setText("File"); + jScrollPane1.getViewport().setBackground(Color.red); + messagesScrollPane.getViewport().setBackground(Color.red); + messagesScrollPane.setPreferredSize(new Dimension(10, 10)); + classNamesJList.addListSelectionListener(new javax.swing.event.ListSelectionListener() { + + public void valueChanged( ListSelectionEvent e ) { + classNamesJList_valueChanged(e); + } + }); + classNamesJList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + jScrollPane3.setBorder(BorderFactory.createLineBorder(Color.black)); + jScrollPane3.setPreferredSize(new Dimension(100, 100)); + gridLayout4.setRows(4); + gridLayout4.setColumns(1); + gridLayout4.setHgap(1); + jScrollPane4.setBorder(BorderFactory.createLineBorder(Color.black)); + jScrollPane4.setPreferredSize(new Dimension(100, 100)); + pass1TextPane.setBorder(BorderFactory.createRaisedBevelBorder()); + pass1TextPane.setToolTipText(""); + pass1TextPane.setEditable(false); + pass2TextPane.setBorder(BorderFactory.createRaisedBevelBorder()); + pass2TextPane.setEditable(false); + messagesTextPane.setBorder(BorderFactory.createRaisedBevelBorder()); + messagesTextPane.setEditable(false); + newFileMenuItem.setText("New..."); + newFileMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(78, + java.awt.event.KeyEvent.CTRL_MASK, true)); + newFileMenuItem.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed( ActionEvent e ) { + newFileMenuItem_actionPerformed(e); + } + }); + pass3aTextPane.setEditable(false); + pass3bTextPane.setEditable(false); + pass3aJList.addListSelectionListener(new javax.swing.event.ListSelectionListener() { + + public void valueChanged( ListSelectionEvent e ) { + pass3aJList_valueChanged(e); + } + }); + pass3bJList.addListSelectionListener(new javax.swing.event.ListSelectionListener() { + + public void valueChanged( ListSelectionEvent e ) { + pass3bJList_valueChanged(e); + } + }); + jMenu2.setText("Help"); + whatisMenuItem.setText("What is..."); + whatisMenuItem.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed( ActionEvent e ) { + whatisMenuItem_actionPerformed(e); + } + }); + aboutMenuItem.setText("About"); + aboutMenuItem.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed( ActionEvent e ) { + aboutMenuItem_actionPerformed(e); + } + }); + jSplitPane2.add(messagesPanel, JSplitPane.BOTTOM); + messagesPanel.add(messagesScrollPane, null); + messagesScrollPane.getViewport().add(messagesTextPane, null); + jSplitPane2.add(jPanel3, JSplitPane.TOP); + jPanel3.add(jScrollPane3, null); + jScrollPane3.getViewport().add(pass1TextPane, null); + jPanel3.add(jScrollPane4, null); + jPanel3.add(jSplitPane3, null); + jSplitPane3.add(jScrollPane2, JSplitPane.LEFT); + jScrollPane2.getViewport().add(pass3aJList, null); + jSplitPane3.add(jScrollPane5, JSplitPane.RIGHT); + jScrollPane5.getViewport().add(pass3aTextPane, null); + jPanel3.add(jSplitPane4, null); + jSplitPane4.add(jScrollPane6, JSplitPane.LEFT); + jScrollPane6.getViewport().add(pass3bJList, null); + jSplitPane4.add(jScrollPane7, JSplitPane.RIGHT); + jScrollPane7.getViewport().add(pass3bTextPane, null); + jScrollPane4.getViewport().add(pass2TextPane, null); + jSplitPane1.add(jPanel2, JSplitPane.TOP); + jPanel2.add(jScrollPane1, null); + jSplitPane1.add(jPanel1, JSplitPane.BOTTOM); + jPanel1.add(jSplitPane2, null); + jScrollPane1.getViewport().add(classNamesJList, null); + jMenuBar1.add(jMenu1); + jMenuBar1.add(jMenu2); + contentPane.add(jSplitPane1, "jSplitPane1"); + jMenu1.add(newFileMenuItem); + jMenu2.add(whatisMenuItem); + jMenu2.add(aboutMenuItem); + jSplitPane2.setDividerLocation(300); + jSplitPane3.setDividerLocation(150); + jSplitPane4.setDividerLocation(150); + } + + + /** Overridden to stop the application on a closing window. */ + protected void processWindowEvent( WindowEvent e ) { + super.processWindowEvent(e); + if (e.getID() == WindowEvent.WINDOW_CLOSING) { + System.exit(0); + } + } + + + synchronized void classNamesJList_valueChanged( ListSelectionEvent e ) { + if (e.getValueIsAdjusting()) { + return; + } + current_class = classNamesJList.getSelectedValue().toString(); + try { + verify(); + } catch (ClassNotFoundException ex) { + // FIXME: report the error using the GUI + ex.printStackTrace(); + } + classNamesJList.setSelectedValue(current_class, true); + } + + + private void verify() throws ClassNotFoundException { + setTitle("PLEASE WAIT"); + Verifier v = VerifierFactory.getVerifier(current_class); + v.flush(); // Don't cache the verification result for this class. + VerificationResult vr; + vr = v.doPass1(); + if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) { + pass1TextPane.setText(vr.getMessage()); + pass1TextPane.setBackground(Color.red); + pass2TextPane.setText(""); + pass2TextPane.setBackground(Color.yellow); + pass3aTextPane.setText(""); + pass3aJList.setListData(new Object[0]); + pass3aTextPane.setBackground(Color.yellow); + pass3bTextPane.setText(""); + pass3bJList.setListData(new Object[0]); + pass3bTextPane.setBackground(Color.yellow); + } else { // Must be VERIFIED_OK, Pass 1 does not know VERIFIED_NOTYET + pass1TextPane.setBackground(Color.green); + pass1TextPane.setText(vr.getMessage()); + vr = v.doPass2(); + if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) { + pass2TextPane.setText(vr.getMessage()); + pass2TextPane.setBackground(Color.red); + pass3aTextPane.setText(""); + pass3aTextPane.setBackground(Color.yellow); + pass3aJList.setListData(new Object[0]); + pass3bTextPane.setText(""); + pass3bTextPane.setBackground(Color.yellow); + pass3bJList.setListData(new Object[0]); + } else { // must be Verified_OK, because Pass1 was OK (cannot be Verified_NOTYET). + pass2TextPane.setText(vr.getMessage()); + pass2TextPane.setBackground(Color.green); + JavaClass jc = Repository.lookupClass(current_class); + /* + boolean all3aok = true; + boolean all3bok = true; + String all3amsg = ""; + String all3bmsg = ""; + */ + String[] methodnames = new String[jc.getMethods().length]; + for (int i = 0; i < jc.getMethods().length; i++) { + methodnames[i] = jc.getMethods()[i].toString().replace('\n', ' ').replace('\t', + ' '); + } + pass3aJList.setListData(methodnames); + pass3aJList.setSelectionInterval(0, jc.getMethods().length - 1); + pass3bJList.setListData(methodnames); + pass3bJList.setSelectionInterval(0, jc.getMethods().length - 1); + } + } + String[] msgs = v.getMessages(); + messagesTextPane.setBackground(msgs.length == 0 ? Color.green : Color.yellow); + String allmsgs = ""; + for (int i = 0; i < msgs.length; i++) { + msgs[i] = msgs[i].replace('\n', ' '); + allmsgs += msgs[i] + "\n\n"; + } + messagesTextPane.setText(allmsgs); + setTitle(current_class + " - " + JUSTICE_VERSION); + } + + + void newFileMenuItem_actionPerformed( ActionEvent e ) { + String classname = JOptionPane + .showInputDialog("Please enter the fully qualified name of a class or interface to verify:"); + if ((classname == null) || (classname.equals(""))) { + return; + } + VerifierFactory.getVerifier(classname); // let observers do the rest. + classNamesJList.setSelectedValue(classname, true); + } + + + synchronized void pass3aJList_valueChanged( ListSelectionEvent e ) { + if (e.getValueIsAdjusting()) { + return; + } + Verifier v = VerifierFactory.getVerifier(current_class); + String all3amsg = ""; + boolean all3aok = true; + boolean rejected = false; + for (int i = 0; i < pass3aJList.getModel().getSize(); i++) { + if (pass3aJList.isSelectedIndex(i)) { + VerificationResult vr = v.doPass3a(i); + if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) { + all3aok = false; + rejected = true; + } + JavaClass jc = null; + try { + jc = Repository.lookupClass(v.getClassName()); + all3amsg += "Method '" + jc.getMethods()[i] + "': " + + vr.getMessage().replace('\n', ' ') + "\n\n"; + } catch (ClassNotFoundException ex) { + // FIXME: handle the error + ex.printStackTrace(); + } + } + } + pass3aTextPane.setText(all3amsg); + pass3aTextPane.setBackground(all3aok ? Color.green : (rejected ? Color.red : Color.yellow)); + } + + + synchronized void pass3bJList_valueChanged( ListSelectionEvent e ) { + if (e.getValueIsAdjusting()) { + return; + } + Verifier v = VerifierFactory.getVerifier(current_class); + String all3bmsg = ""; + boolean all3bok = true; + boolean rejected = false; + for (int i = 0; i < pass3bJList.getModel().getSize(); i++) { + if (pass3bJList.isSelectedIndex(i)) { + VerificationResult vr = v.doPass3b(i); + if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) { + all3bok = false; + rejected = true; + } + JavaClass jc = null; + try { + jc = Repository.lookupClass(v.getClassName()); + all3bmsg += "Method '" + jc.getMethods()[i] + "': " + + vr.getMessage().replace('\n', ' ') + "\n\n"; + } catch (ClassNotFoundException ex) { + // FIXME: handle the error + ex.printStackTrace(); + } + } + } + pass3bTextPane.setText(all3bmsg); + pass3bTextPane.setBackground(all3bok ? Color.green : (rejected ? Color.red : Color.yellow)); + } + + + void aboutMenuItem_actionPerformed( ActionEvent e ) { + JOptionPane + .showMessageDialog( + this, + "JustIce is a Java class file verifier.\nIt was implemented by Enver Haase in 2001, 2002.\n", + JUSTICE_VERSION, JOptionPane.INFORMATION_MESSAGE); + } + + + void whatisMenuItem_actionPerformed( ActionEvent e ) { + JOptionPane + .showMessageDialog( + this, + "The upper four boxes to the right reflect verification passes according to The Java Virtual Machine Specification.\nThese are (in that order): Pass one, Pass two, Pass three (before data flow analysis), Pass three (data flow analysis).\nThe bottom box to the right shows (warning) messages; warnings do not cause a class to be rejected.", + JUSTICE_VERSION, JOptionPane.INFORMATION_MESSAGE); + } +} diff --git a/src/org/apache/bcel/verifier/VerifierFactory.java b/src/org/apache/bcel/verifier/VerifierFactory.java new file mode 100644 index 0000000..bb9f0bb --- /dev/null +++ b/src/org/apache/bcel/verifier/VerifierFactory.java @@ -0,0 +1,110 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +/** + * This class produces instances of the Verifier class. Its purpose is to make + * sure that they are singleton instances with respect to the class name they + * operate on. That means, for every class (represented by a unique fully qualified + * class name) there is exactly one Verifier. + * + * @version $Id: VerifierFactory.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + * @see org.apache.bcel.verifier.Verifier + */ +public class VerifierFactory { + + /** + * The HashMap that holds the data about the already-constructed Verifier instances. + */ + private static Map hashMap = new HashMap(); + /** + * The VerifierFactoryObserver instances that observe the VerifierFactory. + */ + private static List observers = new Vector(); + + + /** + * The VerifierFactory is not instantiable. + */ + private VerifierFactory() { + } + + + /** + * Returns the (only) verifier responsible for the class with the given name. + * Possibly a new Verifier object is transparently created. + * @return the (only) verifier responsible for the class with the given name. + */ + public static Verifier getVerifier( String fully_qualified_classname ) { + Verifier v = (Verifier) (hashMap.get(fully_qualified_classname)); + if (v == null) { + v = new Verifier(fully_qualified_classname); + hashMap.put(fully_qualified_classname, v); + notify(fully_qualified_classname); + } + return v; + } + + + /** + * Notifies the observers of a newly generated Verifier. + */ + private static void notify( String fully_qualified_classname ) { + // notify the observers + Iterator i = observers.iterator(); + while (i.hasNext()) { + VerifierFactoryObserver vfo = (VerifierFactoryObserver) i.next(); + vfo.update(fully_qualified_classname); + } + } + + + /** + * Returns all Verifier instances created so far. + * This is useful when a Verifier recursively lets + * the VerifierFactory create other Verifier instances + * and if you want to verify the transitive hull of + * referenced class files. + */ + public static Verifier[] getVerifiers() { + Verifier[] vs = new Verifier[hashMap.values().size()]; + return (Verifier[]) (hashMap.values().toArray(vs)); // Because vs is big enough, vs is used to store the values into and returned! + } + + + /** + * Adds the VerifierFactoryObserver o to the list of observers. + */ + public static void attach( VerifierFactoryObserver o ) { + observers.add(o); + } + + + /** + * Removes the VerifierFactoryObserver o from the list of observers. + */ + public static void detach( VerifierFactoryObserver o ) { + observers.remove(o); + } +} diff --git a/src/org/apache/bcel/verifier/VerifierFactoryListModel.java b/src/org/apache/bcel/verifier/VerifierFactoryListModel.java new file mode 100644 index 0000000..1eb9bbf --- /dev/null +++ b/src/org/apache/bcel/verifier/VerifierFactoryListModel.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +import javax.swing.event.ListDataEvent; + +/** + * This class implements an adapter; it implements both a Swing ListModel and + * a VerifierFactoryObserver. + * + * @version $Id: VerifierFactoryListModel.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public class VerifierFactoryListModel implements org.apache.bcel.verifier.VerifierFactoryObserver, + javax.swing.ListModel { + + private java.util.ArrayList listeners = new java.util.ArrayList(); + private java.util.TreeSet cache = new java.util.TreeSet(); + + + public VerifierFactoryListModel() { + VerifierFactory.attach(this); + update(null); // fill cache. + } + + + public synchronized void update( String s ) { + int size = listeners.size(); + Verifier[] verifiers = VerifierFactory.getVerifiers(); + int num_of_verifiers = verifiers.length; + cache.clear(); + for (int i = 0; i < num_of_verifiers; i++) { + cache.add(verifiers[i].getClassName()); + } + for (int i = 0; i < size; i++) { + ListDataEvent e = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, + num_of_verifiers - 1); + ((javax.swing.event.ListDataListener) (listeners.get(i))).contentsChanged(e); + } + } + + + public synchronized void addListDataListener( javax.swing.event.ListDataListener l ) { + listeners.add(l); + } + + + public synchronized void removeListDataListener( javax.swing.event.ListDataListener l ) { + listeners.remove(l); + } + + + public synchronized int getSize() { + return cache.size(); + } + + + public synchronized Object getElementAt( int index ) { + return (cache.toArray())[index]; + } +} diff --git a/src/org/apache/bcel/verifier/VerifierFactoryObserver.java b/src/org/apache/bcel/verifier/VerifierFactoryObserver.java new file mode 100644 index 0000000..70dcc0f --- /dev/null +++ b/src/org/apache/bcel/verifier/VerifierFactoryObserver.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +/** + * VerifierFactoryObserver instances are notified when new Verifier + * instances are created. + * + * @version $Id: VerifierFactoryObserver.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + * + * @see VerifierFactory#getVerifier(String) + * @see VerifierFactory#getVerifiers() + * @see VerifierFactory#attach(VerifierFactoryObserver) + * @see VerifierFactory#detach(VerifierFactoryObserver) + */ +public interface VerifierFactoryObserver { + + /** + * VerifierFactoryObserver instances are notified invoking this method. + * The String argument is the fully qualified class name of a class a + * new Verifier instance created by the VerifierFactory operates on. + */ + public void update( String s ); +} diff --git a/src/org/apache/bcel/verifier/VerifyDialog.java b/src/org/apache/bcel/verifier/VerifyDialog.java new file mode 100644 index 0000000..4a89f51 --- /dev/null +++ b/src/org/apache/bcel/verifier/VerifyDialog.java @@ -0,0 +1,553 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier; + +import java.awt.Color; +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.JavaClass; + +/** + * A class for simple graphical class file verification. + * Use the main(String []) method with fully qualified + * class names as arguments to use it as a stand-alone + * application. + * Use the VerifyDialog(String) constructor to use this + * class in your application. + * [This class was created using VisualAge for Java, + * but it does not work under VAJ itself (Version 3.02 JDK 1.2)] + * @version $Id: VerifyDialog.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + * @see #main(String[]) + * @see #VerifyDialog(String) + */ +public class VerifyDialog extends javax.swing.JDialog { + + /** Machine-generated. */ + private javax.swing.JPanel ivjJDialogContentPane = null; + /** Machine-generated. */ + private javax.swing.JPanel ivjPass1Panel = null; + /** Machine-generated. */ + private javax.swing.JPanel ivjPass2Panel = null; + /** Machine-generated. */ + private javax.swing.JPanel ivjPass3Panel = null; + /** Machine-generated. */ + private javax.swing.JButton ivjPass1Button = null; + /** Machine-generated. */ + private javax.swing.JButton ivjPass2Button = null; + /** Machine-generated. */ + private javax.swing.JButton ivjPass3Button = null; + /** Machine-generated. */ + IvjEventHandler ivjEventHandler = new IvjEventHandler(); + /** + * The class to verify. Default set to 'java.lang.Object' + * in case this class is instantiated via one of the many + * machine-generated constructors. + */ + private String class_name = "java.lang.Object"; + /** + * This field is here to count the number of open VerifyDialog + * instances so the JVM can be exited afer every Dialog had been + * closed. + */ + private static int classes_to_verify; + + /** Machine-generated. */ + class IvjEventHandler implements java.awt.event.ActionListener { + + public void actionPerformed( java.awt.event.ActionEvent e ) { + if (e.getSource() == VerifyDialog.this.getPass1Button()) { + connEtoC1(e); + } + if (e.getSource() == VerifyDialog.this.getPass2Button()) { + connEtoC2(e); + } + if (e.getSource() == VerifyDialog.this.getPass3Button()) { + connEtoC3(e); + } + if (e.getSource() == VerifyDialog.this.getFlushButton()) { + connEtoC4(e); + } + }; + }; + + /** Machine-generated. */ + private javax.swing.JButton ivjFlushButton = null; + + + /** Machine-generated. */ + public VerifyDialog() { + super(); + initialize(); + } + + + /** Machine-generated. */ + public VerifyDialog(java.awt.Dialog owner) { + super(owner); + } + + + /** Machine-generated. */ + public VerifyDialog(java.awt.Dialog owner, String title) { + super(owner, title); + } + + + /** Machine-generated. */ + public VerifyDialog(java.awt.Dialog owner, String title, boolean modal) { + super(owner, title, modal); + } + + + /** Machine-generated. */ + public VerifyDialog(java.awt.Dialog owner, boolean modal) { + super(owner, modal); + } + + + /** Machine-generated. */ + public VerifyDialog(java.awt.Frame owner) { + super(owner); + } + + + /** Machine-generated. */ + public VerifyDialog(java.awt.Frame owner, String title) { + super(owner, title); + } + + + /** Machine-generated. */ + public VerifyDialog(java.awt.Frame owner, String title, boolean modal) { + super(owner, title, modal); + } + + + /** Machine-generated. */ + public VerifyDialog(java.awt.Frame owner, boolean modal) { + super(owner, modal); + } + + + /** + * Use this constructor if you want a possibility to verify other + * class files than java.lang.Object. + * @param fully_qualified_class_name java.lang.String + */ + public VerifyDialog(String fully_qualified_class_name) { + super(); + int dotclasspos = fully_qualified_class_name.lastIndexOf(".class"); + if (dotclasspos != -1) { + fully_qualified_class_name = fully_qualified_class_name.substring(0, dotclasspos); + } + fully_qualified_class_name = fully_qualified_class_name.replace('/', '.'); + class_name = fully_qualified_class_name; + initialize(); + } + + + /** Machine-generated. */ + private void connEtoC1( java.awt.event.ActionEvent arg1 ) { + try { + // user code begin {1} + // user code end + this.pass1Button_ActionPerformed(arg1); + // user code begin {2} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {3} + // user code end + handleException(ivjExc); + } + } + + + /** Machine-generated. */ + private void connEtoC2( java.awt.event.ActionEvent arg1 ) { + try { + // user code begin {1} + // user code end + this.pass2Button_ActionPerformed(arg1); + // user code begin {2} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {3} + // user code end + handleException(ivjExc); + } + } + + + /** Machine-generated. */ + private void connEtoC3( java.awt.event.ActionEvent arg1 ) { + try { + // user code begin {1} + // user code end + this.pass4Button_ActionPerformed(arg1); + // user code begin {2} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {3} + // user code end + handleException(ivjExc); + } + } + + + /** Machine-generated. */ + private void connEtoC4( java.awt.event.ActionEvent arg1 ) { + try { + // user code begin {1} + // user code end + this.flushButton_ActionPerformed(arg1); + // user code begin {2} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {3} + // user code end + handleException(ivjExc); + } + } + + + /** Machine-generated. */ + public void flushButton_ActionPerformed( java.awt.event.ActionEvent actionEvent ) { + VerifierFactory.getVerifier(class_name).flush(); + Repository.removeClass(class_name); // Make sure it will be reloaded. + getPass1Panel().setBackground(Color.gray); + getPass1Panel().repaint(); + getPass2Panel().setBackground(Color.gray); + getPass2Panel().repaint(); + getPass3Panel().setBackground(Color.gray); + getPass3Panel().repaint(); + } + + + /** Machine-generated. */ + private javax.swing.JButton getFlushButton() { + if (ivjFlushButton == null) { + try { + ivjFlushButton = new javax.swing.JButton(); + ivjFlushButton.setName("FlushButton"); + ivjFlushButton.setText("Flush: Forget old verification results"); + ivjFlushButton.setBackground(java.awt.SystemColor.controlHighlight); + ivjFlushButton.setBounds(60, 215, 300, 30); + ivjFlushButton.setForeground(java.awt.Color.red); + ivjFlushButton.setActionCommand("FlushButton"); + // user code begin {1} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {2} + // user code end + handleException(ivjExc); + } + } + return ivjFlushButton; + } + + + /** Machine-generated. */ + private javax.swing.JPanel getJDialogContentPane() { + if (ivjJDialogContentPane == null) { + try { + ivjJDialogContentPane = new javax.swing.JPanel(); + ivjJDialogContentPane.setName("JDialogContentPane"); + ivjJDialogContentPane.setLayout(null); + getJDialogContentPane().add(getPass1Panel(), getPass1Panel().getName()); + getJDialogContentPane().add(getPass3Panel(), getPass3Panel().getName()); + getJDialogContentPane().add(getPass2Panel(), getPass2Panel().getName()); + getJDialogContentPane().add(getPass1Button(), getPass1Button().getName()); + getJDialogContentPane().add(getPass2Button(), getPass2Button().getName()); + getJDialogContentPane().add(getPass3Button(), getPass3Button().getName()); + getJDialogContentPane().add(getFlushButton(), getFlushButton().getName()); + // user code begin {1} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {2} + // user code end + handleException(ivjExc); + } + } + return ivjJDialogContentPane; + } + + + /** Machine-generated. */ + private javax.swing.JButton getPass1Button() { + if (ivjPass1Button == null) { + try { + ivjPass1Button = new javax.swing.JButton(); + ivjPass1Button.setName("Pass1Button"); + ivjPass1Button.setText("Pass1: Verify binary layout of .class file"); + ivjPass1Button.setBackground(java.awt.SystemColor.controlHighlight); + ivjPass1Button.setBounds(100, 40, 300, 30); + ivjPass1Button.setActionCommand("Button1"); + // user code begin {1} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {2} + // user code end + handleException(ivjExc); + } + } + return ivjPass1Button; + } + + + /** Machine-generated. */ + private javax.swing.JPanel getPass1Panel() { + if (ivjPass1Panel == null) { + try { + ivjPass1Panel = new javax.swing.JPanel(); + ivjPass1Panel.setName("Pass1Panel"); + ivjPass1Panel.setLayout(null); + ivjPass1Panel.setBackground(java.awt.SystemColor.controlShadow); + ivjPass1Panel.setBounds(30, 30, 50, 50); + // user code begin {1} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {2} + // user code end + handleException(ivjExc); + } + } + return ivjPass1Panel; + } + + + /** Machine-generated. */ + private javax.swing.JButton getPass2Button() { + if (ivjPass2Button == null) { + try { + ivjPass2Button = new javax.swing.JButton(); + ivjPass2Button.setName("Pass2Button"); + ivjPass2Button.setText("Pass 2: Verify static .class file constraints"); + ivjPass2Button.setBackground(java.awt.SystemColor.controlHighlight); + ivjPass2Button.setBounds(100, 100, 300, 30); + ivjPass2Button.setActionCommand("Button2"); + // user code begin {1} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {2} + // user code end + handleException(ivjExc); + } + } + return ivjPass2Button; + } + + + /** Machine-generated. */ + private javax.swing.JPanel getPass2Panel() { + if (ivjPass2Panel == null) { + try { + ivjPass2Panel = new javax.swing.JPanel(); + ivjPass2Panel.setName("Pass2Panel"); + ivjPass2Panel.setLayout(null); + ivjPass2Panel.setBackground(java.awt.SystemColor.controlShadow); + ivjPass2Panel.setBounds(30, 90, 50, 50); + // user code begin {1} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {2} + // user code end + handleException(ivjExc); + } + } + return ivjPass2Panel; + } + + + /** Machine-generated. */ + private javax.swing.JButton getPass3Button() { + if (ivjPass3Button == null) { + try { + ivjPass3Button = new javax.swing.JButton(); + ivjPass3Button.setName("Pass3Button"); + ivjPass3Button.setText("Passes 3a+3b: Verify code arrays"); + ivjPass3Button.setBackground(java.awt.SystemColor.controlHighlight); + ivjPass3Button.setBounds(100, 160, 300, 30); + ivjPass3Button.setActionCommand("Button2"); + // user code begin {1} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {2} + // user code end + handleException(ivjExc); + } + } + return ivjPass3Button; + } + + + /** Machine-generated. */ + private javax.swing.JPanel getPass3Panel() { + if (ivjPass3Panel == null) { + try { + ivjPass3Panel = new javax.swing.JPanel(); + ivjPass3Panel.setName("Pass3Panel"); + ivjPass3Panel.setLayout(null); + ivjPass3Panel.setBackground(java.awt.SystemColor.controlShadow); + ivjPass3Panel.setBounds(30, 150, 50, 50); + // user code begin {1} + // user code end + } catch (java.lang.Throwable ivjExc) { + // user code begin {2} + // user code end + handleException(ivjExc); + } + } + return ivjPass3Panel; + } + + + /** Machine-generated. */ + private void handleException( java.lang.Throwable exception ) { + /* Uncomment the following lines to print uncaught exceptions to stdout */ + System.out.println("--------- UNCAUGHT EXCEPTION ---------"); + exception.printStackTrace(System.out); + } + + + /** Machine-generated. */ + private void initConnections() throws java.lang.Exception { + // user code begin {1} + // user code end + getPass1Button().addActionListener(ivjEventHandler); + getPass2Button().addActionListener(ivjEventHandler); + getPass3Button().addActionListener(ivjEventHandler); + getFlushButton().addActionListener(ivjEventHandler); + } + + + /** Machine-generated. */ + private void initialize() { + try { + // user code begin {1} + // user code end + setName("VerifyDialog"); + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setSize(430, 280); + setVisible(true); + setModal(true); + setResizable(false); + setContentPane(getJDialogContentPane()); + initConnections(); + } catch (java.lang.Throwable ivjExc) { + handleException(ivjExc); + } + // user code begin {2} + setTitle("'" + class_name + "' verification - JustIce / BCEL"); + // user code end + } + + + /** + * Verifies one or more class files. + * Verification results are presented graphically: Red means 'rejected', + * green means 'passed' while yellow means 'could not be verified yet'. + * @param args java.lang.String[] fully qualified names of classes to verify. + */ + public static void main( java.lang.String[] args ) { + classes_to_verify = args.length; + for (int i = 0; i < args.length; i++) { + try { + VerifyDialog aVerifyDialog; + aVerifyDialog = new VerifyDialog(args[i]); + aVerifyDialog.setModal(true); + aVerifyDialog.addWindowListener(new java.awt.event.WindowAdapter() { + + public void windowClosing( java.awt.event.WindowEvent e ) { + classes_to_verify--; + if (classes_to_verify == 0) { + System.exit(0); + } + }; + }); + aVerifyDialog.setVisible(true); + } catch (Throwable exception) { + System.err.println("Exception occurred in main() of javax.swing.JDialog"); + exception.printStackTrace(System.out); + } + } + } + + + /** Machine-generated. */ + public void pass1Button_ActionPerformed( java.awt.event.ActionEvent actionEvent ) { + Verifier v = VerifierFactory.getVerifier(class_name); + VerificationResult vr = v.doPass1(); + if (vr.getStatus() == VerificationResult.VERIFIED_OK) { + getPass1Panel().setBackground(Color.green); + getPass1Panel().repaint(); + } + if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) { + getPass1Panel().setBackground(Color.red); + getPass1Panel().repaint(); + } + } + + + /** Machine-generated. */ + public void pass2Button_ActionPerformed( java.awt.event.ActionEvent actionEvent ) { + pass1Button_ActionPerformed(actionEvent); + Verifier v = VerifierFactory.getVerifier(class_name); + VerificationResult vr = v.doPass2(); + if (vr.getStatus() == VerificationResult.VERIFIED_OK) { + getPass2Panel().setBackground(Color.green); + getPass2Panel().repaint(); + } + if (vr.getStatus() == VerificationResult.VERIFIED_NOTYET) { + getPass2Panel().setBackground(Color.yellow); + getPass2Panel().repaint(); + } + if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) { + getPass2Panel().setBackground(Color.red); + getPass2Panel().repaint(); + } + } + + + /** Machine-generated. */ + public void pass4Button_ActionPerformed( java.awt.event.ActionEvent actionEvent ) { + pass2Button_ActionPerformed(actionEvent); + Color color = Color.green; + Verifier v = VerifierFactory.getVerifier(class_name); + VerificationResult vr = v.doPass2(); + if (vr.getStatus() == VerificationResult.VERIFIED_OK) { + JavaClass jc = null; + try { + jc = Repository.lookupClass(class_name); + int nr = jc.getMethods().length; + for (int i = 0; i < nr; i++) { + vr = v.doPass3b(i); + if (vr.getStatus() != VerificationResult.VERIFIED_OK) { + color = Color.red; + break; + } + } + } catch (ClassNotFoundException ex) { + // FIXME: report the error + ex.printStackTrace(); + } + } else { + color = Color.yellow; + } + getPass3Panel().setBackground(color); + getPass3Panel().repaint(); + } +} diff --git a/src/org/apache/bcel/verifier/exc/AssertionViolatedException.java b/src/org/apache/bcel/verifier/exc/AssertionViolatedException.java new file mode 100644 index 0000000..6aea937 --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/AssertionViolatedException.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + + +/** + * Instances of this class should never be thrown. When such an instance is thrown, + * this is due to an INTERNAL ERROR of BCEL's class file verifier "JustIce". + * + * @version $Id: AssertionViolatedException.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public final class AssertionViolatedException extends RuntimeException{ + /** The error message. */ + private String detailMessage; + /** Constructs a new AssertionViolatedException with null as its error message string. */ + public AssertionViolatedException(){ + super(); + } + /** + * Constructs a new AssertionViolatedException with the specified error message preceded + * by "INTERNAL ERROR: ". + */ + public AssertionViolatedException(String message){ + super(message = "INTERNAL ERROR: "+message); // Thanks to Java, the constructor call here must be first. + detailMessage=message; + } + /** Extends the error message with a string before ("pre") and after ("post") the + 'old' error message. All of these three strings are allowed to be null, and null + is always replaced by the empty string (""). In particular, after invoking this + method, the error message of this object can no longer be null. + */ + public void extendMessage(String pre, String post){ + if (pre == null) { + pre=""; + } + if (detailMessage == null) { + detailMessage=""; + } + if (post == null) { + post=""; + } + detailMessage = pre+detailMessage+post; + } + /** + * Returns the error message string of this AssertionViolatedException object. + * @return the error message string of this AssertionViolatedException. + */ + public String getMessage(){ + return detailMessage; + } + + /** + * DO NOT USE. It's for experimental testing during development only. + */ + public static void main(String[] args){ + AssertionViolatedException ave = new AssertionViolatedException("Oops!"); + ave.extendMessage("\nFOUND:\n\t","\nExiting!!\n"); + throw ave; + } + +} diff --git a/src/org/apache/bcel/verifier/exc/ClassConstraintException.java b/src/org/apache/bcel/verifier/exc/ClassConstraintException.java new file mode 100644 index 0000000..3230d89 --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/ClassConstraintException.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + + +/** + * Instances of this class are thrown by BCEL's class file verifier "JustIce" + * when a class file to verify does not pass the verification pass 2 as described + * in the Java Virtual Machine specification, 2nd edition. + * + * @version $Id: ClassConstraintException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public class ClassConstraintException extends VerificationException{ + /** + * Constructs a new ClassConstraintException with null as its error message string. + */ + public ClassConstraintException(){ + super(); + } + + /** + * Constructs a new ClassConstraintException with the specified error message. + */ + public ClassConstraintException(String message){ + super (message); + } +} diff --git a/src/org/apache/bcel/verifier/exc/CodeConstraintException.java b/src/org/apache/bcel/verifier/exc/CodeConstraintException.java new file mode 100644 index 0000000..82d1b2f --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/CodeConstraintException.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + +/** + * Instances of this class are thrown by BCEL's class file verifier "JustIce" when + * a class file does not pass the verification pass 3. Note that the pass 3 used by + * "JustIce" involves verification that is usually delayed to pass 4. + * + * @version $Id: CodeConstraintException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public abstract class CodeConstraintException extends VerificationException{ + /** + * Constructs a new CodeConstraintException with null as its error message string. + */ + CodeConstraintException(){ + super(); + } + /** + * Constructs a new CodeConstraintException with the specified error message. + */ + CodeConstraintException(String message){ + super(message); + } +} diff --git a/src/org/apache/bcel/verifier/exc/InvalidMethodException.java b/src/org/apache/bcel/verifier/exc/InvalidMethodException.java new file mode 100644 index 0000000..548afab --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/InvalidMethodException.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + +/** + * Instances of this class are thrown by BCEL's class file verifier "JustIce" + * when the verification of a method is requested that does not exist. + * + * @version $Id: InvalidMethodException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public class InvalidMethodException extends RuntimeException{ + + /** Constructs an InvalidMethodException with the specified detail message. */ + public InvalidMethodException(String message){ + super(message); + } +} diff --git a/src/org/apache/bcel/verifier/exc/LinkingConstraintException.java b/src/org/apache/bcel/verifier/exc/LinkingConstraintException.java new file mode 100644 index 0000000..63cee55 --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/LinkingConstraintException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + +/** + * Instances of this class are thrown by BCEL's class file verifier "JustIce" when + * a class file to verify does not pass the verification pass 3 because of a violation + * of a constraint that is usually only verified at run-time (pass 4). + * The Java Virtual Machine Specification, 2nd edition, states that certain constraints + * are usually verified at run-time for performance reasons (the verification of those + * constraints requires loading in and recursively verifying referenced classes) that + * conceptually belong to pass 3; to be precise, that conceptually belong to the + * data flow analysis of pass 3 (called pass 3b in JustIce). + * These are the checks necessary for resolution: Compare pages 142-143 ("4.9.1 The + * Verification Process") and pages 50-51 ("2.17.3 Linking: Verification, Preparation, + * and Resolution") of the above mentioned book. + * TODO: At this time, this class is not used in JustIce. + * + * @version $Id: LinkingConstraintException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public class LinkingConstraintException extends StructuralCodeConstraintException{ +} diff --git a/src/org/apache/bcel/verifier/exc/LoadingException.java b/src/org/apache/bcel/verifier/exc/LoadingException.java new file mode 100644 index 0000000..7d9d769 --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/LoadingException.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + + +/** + * When loading a class file, BCEL will throw an instance of LoadingException if + * the class file is malformed; so it is not conforming to the "Pass 1" verification + * process as described in the Java Virtual Machine specification, 2nd. edition. + * @version $Id: LoadingException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public class LoadingException extends VerifierConstraintViolatedException{ + + /** + * Constructs a new LoadingException with null as its error message string. + */ + public LoadingException(){ + super(); + } + + /** + * Constructs a new LoadingException with the specified error message. + */ + public LoadingException(String message){ + super (message); + } +} diff --git a/src/org/apache/bcel/verifier/exc/LocalVariableInfoInconsistentException.java b/src/org/apache/bcel/verifier/exc/LocalVariableInfoInconsistentException.java new file mode 100644 index 0000000..ca5fa5d --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/LocalVariableInfoInconsistentException.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + + +/** + * A LocalVariableInfoInconsistentException instance is thrown by + * the LocalVariableInfo class when it detects that the information + * it holds is inconsistent; this is normally due to inconsistent + * LocalVariableTable entries in the Code attribute of a certain + * Method object. + * + * @version $Id: LocalVariableInfoInconsistentException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public class LocalVariableInfoInconsistentException extends ClassConstraintException{ + /** + * Constructs a new LocalVariableInfoInconsistentException with null as its error message string. + */ + public LocalVariableInfoInconsistentException(){ + super(); + } + + /** + * Constructs a new LocalVariableInfoInconsistentException with the specified error message. + */ + public LocalVariableInfoInconsistentException(String message){ + super (message); + } +} diff --git a/src/org/apache/bcel/verifier/exc/StaticCodeConstraintException.java b/src/org/apache/bcel/verifier/exc/StaticCodeConstraintException.java new file mode 100644 index 0000000..ca4859b --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/StaticCodeConstraintException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + + +/** + * Instances of this class are thrown by BCEL's class file verifier "JustIce" when + * a class file to verify does not pass the verification pass 3 because of a violation + * of a static constraint as described in the Java Virtual Machine Specification, + * 2nd edition, 4.8.1, pages 133-137. The static constraints checking part of pass 3 + * is called pass 3a in JustIce. + * + * @version $Id: StaticCodeConstraintException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public abstract class StaticCodeConstraintException extends CodeConstraintException{ + public StaticCodeConstraintException(String message){ + super(message); + } +} diff --git a/src/org/apache/bcel/verifier/exc/StaticCodeInstructionConstraintException.java b/src/org/apache/bcel/verifier/exc/StaticCodeInstructionConstraintException.java new file mode 100644 index 0000000..ce733ea --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/StaticCodeInstructionConstraintException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + + +/** + * Instances of this class are thrown by BCEL's class file verifier "JustIce" when + * a class file to verify does not pass the verification pass 3 because of a violation + * of a static constraint as described in the Java Virtual Machine Specification, + * Second edition, 4.8.1, pages 133-137. The static constraints checking part of pass 3 + * is called pass 3a in JustIce. + * Static constraints on the instructions in the code array are checked early in + * pass 3a and are described on page 134 in the Java Virtual Machine Specification, + * Second Edition. + * + * @version $Id: StaticCodeInstructionConstraintException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public class StaticCodeInstructionConstraintException extends StaticCodeConstraintException{ + public StaticCodeInstructionConstraintException(String message){ + super(message); + } +} diff --git a/src/org/apache/bcel/verifier/exc/StaticCodeInstructionOperandConstraintException.java b/src/org/apache/bcel/verifier/exc/StaticCodeInstructionOperandConstraintException.java new file mode 100644 index 0000000..25afb89 --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/StaticCodeInstructionOperandConstraintException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + + +/** + * Instances of this class are thrown by BCEL's class file verifier "JustIce" when + * a class file to verify does not pass the verification pass 3 because of a violation + * of a static constraint as described in the Java Virtual Machine Specification, + * Second edition, 4.8.1, pages 133-137. The static constraints checking part of pass 3 + * is called pass 3a in JustIce. + * Static constraints on the operands of instructions in the code array are checked late in + * pass 3a and are described on page 134-137 in the Java Virtual Machine Specification, + * Second Edition. + * + * @version $Id: StaticCodeInstructionOperandConstraintException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public class StaticCodeInstructionOperandConstraintException extends StaticCodeConstraintException{ + public StaticCodeInstructionOperandConstraintException(String message){ + super(message); + } +} diff --git a/src/org/apache/bcel/verifier/exc/StructuralCodeConstraintException.java b/src/org/apache/bcel/verifier/exc/StructuralCodeConstraintException.java new file mode 100644 index 0000000..0cfbe99 --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/StructuralCodeConstraintException.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + +/** + * Instances of this class are thrown by BCEL's class file verifier "JustIce" when + * a class file to verify does not pass the verification pass 3 because of a violation + * of a structural constraint as described in the Java Virtual Machine Specification, + * 2nd edition, 4.8.2, pages 137-139. + * Note that the notion of a "structural" constraint is somewhat misleading. Structural + * constraints are constraints on relationships between Java virtual machine instructions. + * These are the constraints where data-flow analysis is needed to verify if they hold. + * The data flow analysis of pass 3 is called pass 3b in JustIce. + * + * @version $Id: StructuralCodeConstraintException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public class StructuralCodeConstraintException extends CodeConstraintException{ + /** + * Constructs a new StructuralCodeConstraintException with the specified error message. + */ + public StructuralCodeConstraintException(String message){ + super(message); + } + /** + * Constructs a new StructuralCodeConstraintException with null as its error message string. + */ + public StructuralCodeConstraintException(){ + super(); + } +} diff --git a/src/org/apache/bcel/verifier/exc/Utility.java b/src/org/apache/bcel/verifier/exc/Utility.java new file mode 100644 index 0000000..ac0b999 --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/Utility.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * A utility class providing convenience methods concerning Throwable instances. + * @version $Id: Utility.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + * @see java.lang.Throwable + */ +public final class Utility{ + /** This class is not instantiable. */ + private Utility(){} + + /** This method returns the stack trace of a Throwable instance as a String. */ + public static String getStackTrace(Throwable t){ + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + t.printStackTrace(pw); + return sw.toString(); + } +} diff --git a/src/org/apache/bcel/verifier/exc/VerificationException.java b/src/org/apache/bcel/verifier/exc/VerificationException.java new file mode 100644 index 0000000..241c519 --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/VerificationException.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + + +/** + * Instances of this class are thrown by BCEL's class file verifier "JustIce" when a + * class file to verify does not pass one of the verification passes 2 or 3. + * Note that the pass 3 used by "JustIce" involves verification that is usually + * delayed to pass 4. + * The name of this class is justified by the Java Virtual Machine Specification, 2nd + * edition, page 164, 5.4.1 where verification as a part of the linking process is + * defined to be the verification happening in passes 2 and 3. + * + * @version $Id: VerificationException.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public abstract class VerificationException extends VerifierConstraintViolatedException{ + /** + * Constructs a new VerificationException with null as its error message string. + */ + VerificationException(){ + super(); + } + /** + * Constructs a new VerificationException with the specified error message. + */ + VerificationException(String message){ + super(message); + } +} diff --git a/src/org/apache/bcel/verifier/exc/VerifierConstraintViolatedException.java b/src/org/apache/bcel/verifier/exc/VerifierConstraintViolatedException.java new file mode 100644 index 0000000..cdb2d54 --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/VerifierConstraintViolatedException.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.exc; + + +/** + * Instances of this class are thrown by BCEL's class file verifier "JustIce" + * whenever + * verification proves that some constraint of a class file (as stated in the + * Java Virtual Machine Specification, Edition 2) is violated. + * This is roughly equivalent to the VerifyError the JVM-internal verifiers + * throw. + * + * @version $Id: VerifierConstraintViolatedException.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public abstract class VerifierConstraintViolatedException extends RuntimeException{ + // /** The name of the offending class that did not pass the verifier. */ + // String name_of_offending_class; + + /** The specified error message. */ + private String detailMessage; + /** + * Constructs a new VerifierConstraintViolatedException with null as its error message string. + */ + VerifierConstraintViolatedException(){ + super(); + } + /** + * Constructs a new VerifierConstraintViolatedException with the specified error message. + */ + VerifierConstraintViolatedException(String message){ + super(message); // Not that important + detailMessage = message; + } + + + /** Extends the error message with a string before ("pre") and after ("post") the + 'old' error message. All of these three strings are allowed to be null, and null + is always replaced by the empty string (""). In particular, after invoking this + method, the error message of this object can no longer be null. + */ + public void extendMessage(String pre, String post){ + if (pre == null) { + pre=""; + } + if (detailMessage == null) { + detailMessage=""; + } + if (post == null) { + post=""; + } + detailMessage = pre+detailMessage+post; + } + /** + * Returns the error message string of this VerifierConstraintViolatedException object. + * @return the error message string of this VerifierConstraintViolatedException. + */ + public String getMessage(){ + return detailMessage; + } +} diff --git a/src/org/apache/bcel/verifier/exc/package.html b/src/org/apache/bcel/verifier/exc/package.html new file mode 100644 index 0000000..fc22276 --- /dev/null +++ b/src/org/apache/bcel/verifier/exc/package.html @@ -0,0 +1,17 @@ + + + + + + + +Exception classes used by JustIce, mostly used internally. You don't need to bother with them. + +

      Package Specification

      + +Contained in this package are Exception classes for use with the JustIce verifier. + + + diff --git a/src/org/apache/bcel/verifier/package.html b/src/org/apache/bcel/verifier/package.html new file mode 100644 index 0000000..9f31ef5 --- /dev/null +++ b/src/org/apache/bcel/verifier/package.html @@ -0,0 +1,18 @@ + + + + + + + +BCEL's verifier JustIce is there to help you dump correct Java class files created or modified with BCEL. + +

      Package Specification

      + +This is the top-level package of the JustIce verifier. To actually use it, have a look at the VerifierFactory and +Verifier classes. + + + diff --git a/src/org/apache/bcel/verifier/statics/DOUBLE_Upper.java b/src/org/apache/bcel/verifier/statics/DOUBLE_Upper.java new file mode 100644 index 0000000..2a104b3 --- /dev/null +++ b/src/org/apache/bcel/verifier/statics/DOUBLE_Upper.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.statics; + + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.Type; + +/** + * This class represents the upper half of a DOUBLE variable. + * @version $Id: DOUBLE_Upper.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public final class DOUBLE_Upper extends Type{ + + /** The one and only instance of this class. */ + private static DOUBLE_Upper singleInstance = new DOUBLE_Upper(); + + /** The constructor; this class must not be instantiated from the outside. */ + private DOUBLE_Upper(){ + super(Constants.T_UNKNOWN, "Long_Upper"); + } + + /** Use this method to get the single instance of this class. */ + public static DOUBLE_Upper theInstance(){ + return singleInstance; + } +} diff --git a/src/org/apache/bcel/verifier/statics/IntList.java b/src/org/apache/bcel/verifier/statics/IntList.java new file mode 100644 index 0000000..5a4a9d2 --- /dev/null +++ b/src/org/apache/bcel/verifier/statics/IntList.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.statics; + + +import java.util.ArrayList; +import java.util.List; + +/** + * A small utility class representing a set of basic int values. + * + * @version $Id: IntList.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public class IntList{ + /** The int are stored as Integer objects here. */ + private List theList; + /** This constructor creates an empty list. */ + IntList(){ + theList = new ArrayList(); + } + /** Adds an element to the list. */ + void add(int i){ + theList.add(new Integer(i)); + } + /** Checks if the specified int is already in the list. */ + boolean contains(int i){ + Integer[] ints = new Integer[theList.size()]; + theList.toArray(ints); + for (int j=0; j= localVariableInfos.length){ + throw new AssertionViolatedException("Slot number for local variable information out of range."); + } + return localVariableInfos[slot]; + } + + /** + * Adds information about the local variable in slot 'slot'. Automatically + * adds information for slot+1 if 't' is Type.LONG or Type.DOUBLE. + * @throws LocalVariableInfoInconsistentException if the new information conflicts + * with already gathered information. + */ + public void add(int slot, String name, int startpc, int length, Type t) throws LocalVariableInfoInconsistentException{ + // The add operation on LocalVariableInfo may throw the '...Inconsistent...' exception, we don't throw it explicitely here. + + if (slot < 0 || slot >= localVariableInfos.length){ + throw new AssertionViolatedException("Slot number for local variable information out of range."); + } + + localVariableInfos[slot].add(name, startpc, length, t); + if (t == Type.LONG) { + localVariableInfos[slot+1].add(name, startpc, length, LONG_Upper.theInstance()); + } + if (t == Type.DOUBLE) { + localVariableInfos[slot+1].add(name, startpc, length, DOUBLE_Upper.theInstance()); + } + } +} diff --git a/src/org/apache/bcel/verifier/statics/Pass1Verifier.java b/src/org/apache/bcel/verifier/statics/Pass1Verifier.java new file mode 100644 index 0000000..5952589 --- /dev/null +++ b/src/org/apache/bcel/verifier/statics/Pass1Verifier.java @@ -0,0 +1,185 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.statics; + + +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.ClassFormatException; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.verifier.PassVerifier; +import org.apache.bcel.verifier.VerificationResult; +import org.apache.bcel.verifier.Verifier; +import org.apache.bcel.verifier.exc.LoadingException; +import org.apache.bcel.verifier.exc.Utility; + +/** + * This PassVerifier verifies a class file according to pass 1 as + * described in The Java Virtual Machine Specification, 2nd edition. + * More detailed information is to be found at the do_verify() method's + * documentation. + * + * @version $Id: Pass1Verifier.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + * @see #do_verify() + */ +public final class Pass1Verifier extends PassVerifier{ + /** + * DON'T USE THIS EVEN PRIVATELY! USE getJavaClass() INSTEAD. + * @see #getJavaClass() + */ + private JavaClass jc; + + /** + * The Verifier that created this. + */ + private Verifier myOwner; + + /** Used to load in and return the myOwner-matching JavaClass object when needed. Avoids loading in a class file when it's not really needed! */ + private JavaClass getJavaClass(){ + if (jc == null){ + try { + jc = Repository.lookupClass(myOwner.getClassName()); + } catch (ClassNotFoundException e) { + // FIXME: currently, Pass1Verifier treats jc == null as a special + // case, so we don't need to do anything here. A better solution + // would be to simply throw the ClassNotFoundException + // out of this method. + } + } + return jc; + } + + /** + * Should only be instantiated by a Verifier. + * + * @see org.apache.bcel.verifier.Verifier + */ + public Pass1Verifier(Verifier owner){ + myOwner = owner; + } + + /** + * Pass-one verification basically means loading in a class file. + * The Java Virtual Machine Specification is not too precise about + * what makes the difference between passes one and two. + * The answer is that only pass one is performed on a class file as + * long as its resolution is not requested; whereas pass two and + * pass three are performed during the resolution process. + * Only four constraints to be checked are explicitely stated by + * The Java Virtual Machine Specification, 2nd edition: + *
        + *
      • The first four bytes must contain the right magic number (0xCAFEBABE). + *
      • All recognized attributes must be of the proper length. + *
      • The class file must not be truncated or have extra bytes at the end. + *
      • The constant pool must not contain any superficially unrecognizable information. + *
      + * A more in-depth documentation of what pass one should do was written by + * Philip W. L. Fong: + *
        + *
      • the file should not be truncated. + *
      • the file should not have extra bytes at the end. + *
      • all variable-length structures should be well-formatted: + *
          + *
        • there should only be constant_pool_count-1 many entries in the constant pool. + *
        • all constant pool entries should have size the same as indicated by their type tag. + *
        • there are exactly interfaces_count many entries in the interfaces array of the class file. + *
        • there are exactly fields_count many entries in the fields array of the class file. + *
        • there are exactly methods_count many entries in the methods array of the class file. + *
        • there are exactly attributes_count many entries in the attributes array of the class file, fields, methods, and code attribute. + *
        • there should be exactly attribute_length many bytes in each attribute. Inconsistency between attribute_length and the actually size of the attribute content should be uncovered. For example, in an Exceptions attribute, the actual number of exceptions as required by the number_of_exceptions field might yeild an attribute size that doesn't match the attribute_length. Such an anomaly should be detected. + *
        • all attributes should have proper length. In particular, under certain context (e.g. while parsing method_info), recognizable attributes (e.g. "Code" attribute) should have correct format (e.g. attribute_length is 2). + *
        + *
      • Also, certain constant values are checked for validity: + *
          + *
        • The magic number should be 0xCAFEBABE. + *
        • The major and minor version numbers are valid. + *
        • All the constant pool type tags are recognizable. + *
        • All undocumented access flags are masked off before use. Strictly speaking, this is not really a check. + *
        • The field this_class should point to a string that represents a legal non-array class name, and this name should be the same as the class file being loaded. + *
        • the field super_class should point to a string that represents a legal non-array class name. + *
        • Because some of the above checks require cross referencing the constant pool entries, guards are set up to make sure that the referenced entries are of the right type and the indices are within the legal range (0 < index < constant_pool_count). + *
        + *
      • Extra checks done in pass 1: + *
          + *
        • the constant values of static fields should have the same type as the fields. + *
        • the number of words in a parameter list does not exceed 255 and locals_max. + *
        • the name and signature of fields and methods are verified to be of legal format. + *
        + *
      + * (From the Paper The Mysterious Pass One, first draft, September 2, 1997.) + *
      + * However, most of this is done by parsing a class file or generating a class file into BCEL's internal data structure. + * Therefore, all that is really done here is look up the class file from BCEL's repository. + * This is also motivated by the fact that some omitted things + * (like the check for extra bytes at the end of the class file) are handy when actually using BCEL to repair a class file (otherwise you would not be + * able to load it into BCEL). + * + * @see org.apache.bcel.Repository + */ + public VerificationResult do_verify(){ + JavaClass jc; + try{ + jc = getJavaClass(); //loads in the class file if not already done. + + if (jc != null){ + /* If we find more constraints to check, we should do this in an own method. */ + if (! myOwner.getClassName().equals(jc.getClassName())){ + // This should maybe caught by BCEL: In case of renamed .class files we get wrong + // JavaClass objects here. + throw new LoadingException("Wrong name: the internal name of the .class file '"+jc.getClassName()+"' does not match the file's name '"+myOwner.getClassName()+"'."); + } + } + + } + catch(LoadingException e){ + return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage()); + } + catch(ClassFormatException e){ + return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage()); + } + catch(RuntimeException e){ + // BCEL does not catch every possible RuntimeException; e.g. if + // a constant pool index is referenced that does not exist. + return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Parsing via BCEL did not succeed. "+e.getClass().getName()+" occured:\n"+Utility.getStackTrace(e)); + } + + if (jc != null){ + return VerificationResult.VR_OK; + } + else{ + //TODO: Maybe change Repository's behaviour to throw a LoadingException instead of just returning "null" + // if a class file cannot be found or in another way be looked up. + return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Repository.lookup() failed. FILE NOT FOUND?"); + } + } + + /** + * Currently this returns an empty array of String. + * One could parse the error messages of BCEL + * (written to java.lang.System.err) when loading + * a class file such as detecting unknown attributes + * or trailing garbage at the end of a class file. + * However, Markus Dahm does not like the idea so this + * method is currently useless and therefore marked as + * TODO. + */ + public String[] getMessages(){ + // This method is only here to override the javadoc-comment. + return super.getMessages(); + } + +} diff --git a/src/org/apache/bcel/verifier/statics/Pass2Verifier.java b/src/org/apache/bcel/verifier/statics/Pass2Verifier.java new file mode 100644 index 0000000..4294229 --- /dev/null +++ b/src/org/apache/bcel/verifier/statics/Pass2Verifier.java @@ -0,0 +1,1444 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.statics; + + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import org.apache.bcel.Constants; +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.Attribute; +import org.apache.bcel.classfile.ClassFormatException; +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.CodeException; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.classfile.ConstantClass; +import org.apache.bcel.classfile.ConstantDouble; +import org.apache.bcel.classfile.ConstantFieldref; +import org.apache.bcel.classfile.ConstantFloat; +import org.apache.bcel.classfile.ConstantInteger; +import org.apache.bcel.classfile.ConstantInterfaceMethodref; +import org.apache.bcel.classfile.ConstantLong; +import org.apache.bcel.classfile.ConstantMethodref; +import org.apache.bcel.classfile.ConstantNameAndType; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.ConstantString; +import org.apache.bcel.classfile.ConstantUtf8; +import org.apache.bcel.classfile.ConstantValue; +import org.apache.bcel.classfile.Deprecated; +import org.apache.bcel.classfile.DescendingVisitor; +import org.apache.bcel.classfile.EmptyVisitor; +import org.apache.bcel.classfile.ExceptionTable; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.InnerClass; +import org.apache.bcel.classfile.InnerClasses; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.LineNumber; +import org.apache.bcel.classfile.LineNumberTable; +import org.apache.bcel.classfile.LocalVariable; +import org.apache.bcel.classfile.LocalVariableTable; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.Node; +import org.apache.bcel.classfile.SourceFile; +import org.apache.bcel.classfile.Synthetic; +import org.apache.bcel.classfile.Unknown; +import org.apache.bcel.classfile.Visitor; +import org.apache.bcel.generic.ArrayType; +import org.apache.bcel.generic.ObjectType; +import org.apache.bcel.generic.Type; +import org.apache.bcel.verifier.PassVerifier; +import org.apache.bcel.verifier.VerificationResult; +import org.apache.bcel.verifier.Verifier; +import org.apache.bcel.verifier.VerifierFactory; +import org.apache.bcel.verifier.exc.AssertionViolatedException; +import org.apache.bcel.verifier.exc.ClassConstraintException; +import org.apache.bcel.verifier.exc.LocalVariableInfoInconsistentException; + +/** + * This PassVerifier verifies a class file according to + * pass 2 as described in The Java Virtual Machine + * Specification, 2nd edition. + * More detailed information is to be found at the do_verify() + * method's documentation. + * + * @version $Id: Pass2Verifier.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + * @see #do_verify() + */ +public final class Pass2Verifier extends PassVerifier implements Constants{ + + /** + * The LocalVariableInfo instances used by Pass3bVerifier. + * localVariablesInfos[i] denotes the information for the + * local variables of method number i in the + * JavaClass this verifier operates on. + */ + private LocalVariablesInfo[] localVariablesInfos; + + /** The Verifier that created this. */ + private Verifier myOwner; + + /** + * Should only be instantiated by a Verifier. + * + * @see Verifier + */ + public Pass2Verifier(Verifier owner){ + myOwner = owner; + } + + /** + * Returns a LocalVariablesInfo object containing information + * about the usage of the local variables in the Code attribute + * of the said method or null if the class file this + * Pass2Verifier operates on could not be pass-2-verified correctly. + * The method number method_nr is the method you get using + * Repository.lookupClass(myOwner.getClassname()).getMethods()[method_nr];. + * You should not add own information. Leave that to JustIce. + */ + public LocalVariablesInfo getLocalVariablesInfo(int method_nr){ + if (this.verify() != VerificationResult.VR_OK) { + return null; // It's cached, don't worry. + } + if (method_nr < 0 || method_nr >= localVariablesInfos.length){ + throw new AssertionViolatedException("Method number out of range."); + } + return localVariablesInfos[method_nr]; + } + + /** + * Pass 2 is the pass where static properties of the + * class file are checked without looking into "Code" + * arrays of methods. + * This verification pass is usually invoked when + * a class is resolved; and it may be possible that + * this verification pass has to load in other classes + * such as superclasses or implemented interfaces. + * Therefore, Pass 1 is run on them.
      + * Note that most referenced classes are not loaded + * in for verification or for an existance check by this + * pass; only the syntactical correctness of their names + * and descriptors (a.k.a. signatures) is checked.
      + * Very few checks that conceptually belong here + * are delayed until pass 3a in JustIce. JustIce does + * not only check for syntactical correctness but also + * for semantical sanity - therefore it needs access to + * the "Code" array of methods in a few cases. Please + * see the pass 3a documentation, too. + * + * @see org.apache.bcel.verifier.statics.Pass3aVerifier + */ + public VerificationResult do_verify(){ + try { + VerificationResult vr1 = myOwner.doPass1(); + if (vr1.equals(VerificationResult.VR_OK)){ + + // For every method, we could have information about the local variables out of LocalVariableTable attributes of + // the Code attributes. + localVariablesInfos = new LocalVariablesInfo[Repository.lookupClass(myOwner.getClassName()).getMethods().length]; + + VerificationResult vr = VerificationResult.VR_OK; // default. + try{ + constant_pool_entries_satisfy_static_constraints(); + field_and_method_refs_are_valid(); + every_class_has_an_accessible_superclass(); + final_methods_are_not_overridden(); + } + catch (ClassConstraintException cce){ + vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage()); + } + return vr; + } else { + return VerificationResult.VR_NOTYET; + } + + } catch (ClassNotFoundException e) { + // FIXME: this might not be the best way to handle missing classes. + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** + * Ensures that every class has a super class and that + * final classes are not subclassed. + * This means, the class this Pass2Verifier operates + * on has proper super classes (transitively) up to + * java.lang.Object. + * The reason for really loading (and Pass1-verifying) + * all of those classes here is that we need them in + * Pass2 anyway to verify no final methods are overridden + * (that could be declared anywhere in the ancestor hierarchy). + * + * @throws ClassConstraintException otherwise. + */ + private void every_class_has_an_accessible_superclass(){ + try { + Set hs = new HashSet(); // save class names to detect circular inheritance + JavaClass jc = Repository.lookupClass(myOwner.getClassName()); + int supidx = -1; + + while (supidx != 0){ + supidx = jc.getSuperclassNameIndex(); + + if (supidx == 0){ + if (jc != Repository.lookupClass(Type.OBJECT.getClassName())){ + throw new ClassConstraintException("Superclass of '"+jc.getClassName()+"' missing but not "+Type.OBJECT.getClassName()+" itself!"); + } + } + else{ + String supername = jc.getSuperclassName(); + if (! hs.add(supername)){ // If supername already is in the list + throw new ClassConstraintException("Circular superclass hierarchy detected."); + } + Verifier v = VerifierFactory.getVerifier(supername); + VerificationResult vr = v.doPass1(); + + if (vr != VerificationResult.VR_OK){ + throw new ClassConstraintException("Could not load in ancestor class '"+supername+"'."); + } + jc = Repository.lookupClass(supername); + + if (jc.isFinal()){ + throw new ClassConstraintException("Ancestor class '"+supername+"' has the FINAL access modifier and must therefore not be subclassed."); + } + } + } + + } catch (ClassNotFoundException e) { + // FIXME: this might not be the best way to handle missing classes. + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** + * Ensures that final methods are not overridden. + * Precondition to run this method: + * constant_pool_entries_satisfy_static_constraints() and + * every_class_has_an_accessible_superclass() have to be invoked before + * (in that order). + * + * @throws ClassConstraintException otherwise. + * @see #constant_pool_entries_satisfy_static_constraints() + * @see #every_class_has_an_accessible_superclass() + */ + private void final_methods_are_not_overridden(){ + try { + Map hashmap = new HashMap(); + JavaClass jc = Repository.lookupClass(myOwner.getClassName()); + + int supidx = -1; + while (supidx != 0){ + supidx = jc.getSuperclassNameIndex(); + + Method[] methods = jc.getMethods(); + for (int i=0; i= cplen)){ + throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(referrer)+"'."); + } + Constant c = cp.getConstant(index); + if (! shouldbe.isInstance(c)){ + /* String isnot = shouldbe.toString().substring(shouldbe.toString().lastIndexOf(".")+1); //Cut all before last "." */ + throw new ClassCastException("Illegal constant '"+tostring(c)+"' at index '"+index+"'. '"+tostring(referrer)+"' expects a '"+shouldbe+"'."); + } + } + /////////////////////////////////////// + // ClassFile structure (vmspec2 4.1) // + /////////////////////////////////////// + public void visitJavaClass(JavaClass obj){ + Attribute[] atts = obj.getAttributes(); + boolean foundSourceFile = false; + boolean foundInnerClasses = false; + + // Is there an InnerClass referenced? + // This is a costly check; existing verifiers don't do it! + boolean hasInnerClass = new InnerClassDetector(jc).innerClassReferenced(); + + for (int i=0; i 1){ + throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set."); + } + + if (obj.isFinal() && obj.isVolatile()){ + throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_FINAL, ACC_VOLATILE modifiers set."); + } + } + else{ // isInterface! + if (!obj.isPublic()){ + throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!"); + } + if (!obj.isStatic()){ + throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!"); + } + if (!obj.isFinal()){ + throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_FINAL modifier set but hasn't!"); + } + } + + if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_VOLATILE|ACC_TRANSIENT)) > 0){ + addMessage("Field '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE, ACC_TRANSIENT set (ignored)."); + } + + checkIndex(obj, obj.getNameIndex(), CONST_Utf8); + + String name = obj.getName(); + if (! validFieldName(name)){ + throw new ClassConstraintException("Field '"+tostring(obj)+"' has illegal name '"+obj.getName()+"'."); + } + + // A descriptor is often named signature in BCEL + checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8); + + String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor) + + try{ + Type.getType(sig); /* Don't need the return value */ + } + catch (ClassFormatException cfe){ + throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); + } + + String nameanddesc = (name+sig); + if (field_names_and_desc.contains(nameanddesc)){ + throw new ClassConstraintException("No two fields (like '"+tostring(obj)+"') are allowed have same names and descriptors!"); + } + if (field_names.contains(name)){ + addMessage("More than one field of name '"+name+"' detected (but with different type descriptors). This is very unusual."); + } + field_names_and_desc.add(nameanddesc); + field_names.add(name); + + Attribute[] atts = obj.getAttributes(); + for (int i=0; i 1){ + throw new ClassConstraintException("Method '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set."); + } + + if (obj.isAbstract()){ + if (obj.isFinal()) { + throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_FINAL modifier set."); + } + if (obj.isNative()) { + throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_NATIVE modifier set."); + } + if (obj.isPrivate()) { + throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_PRIVATE modifier set."); + } + if (obj.isStatic()) { + throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STATIC modifier set."); + } + if (obj.isStrictfp()) { + throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STRICT modifier set."); + } + if (obj.isSynchronized()) { + throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_SYNCHRONIZED modifier set."); + } + } + } + else{ // isInterface! + if (!name.equals(STATIC_INITIALIZER_NAME)){//vmspec2, p.116, 2nd paragraph + if (!obj.isPublic()){ + throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!"); + } + if (!obj.isAbstract()){ + throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!"); + } + if ( obj.isPrivate() || + obj.isProtected() || + obj.isStatic() || + obj.isFinal() || + obj.isSynchronized() || + obj.isNative() || + obj.isStrictfp() ){ + throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must not have any of the ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT modifiers set."); + } + } + } + + // A specific instance initialization method... (vmspec2,Page 116). + if (name.equals(CONSTRUCTOR_NAME)){ + //..may have at most one of ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC set: is checked above. + //..may also have ACC_STRICT set, but none of the other flags in table 4.5 (vmspec2, page 115) + if ( obj.isStatic() || + obj.isFinal() || + obj.isSynchronized() || + obj.isNative() || + obj.isAbstract() ){ + throw new ClassConstraintException("Instance initialization method '"+tostring(obj)+"' must not have any of the ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT modifiers set."); + } + } + + // Class and interface initialization methods... + if (name.equals(STATIC_INITIALIZER_NAME)){ + if ((obj.getAccessFlags() & (~ACC_STRICT)) > 0){ + addMessage("Class or interface initialization method '"+tostring(obj)+"' has superfluous access modifier(s) set: everything but ACC_STRICT is ignored."); + } + if (obj.isAbstract()){ + throw new ClassConstraintException("Class or interface initialization method '"+tostring(obj)+"' must not be abstract. This contradicts the Java Language Specification, Second Edition (which omits this constraint) but is common practice of existing verifiers."); + } + } + + if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) > 0){ + addMessage("Method '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT set (ignored)."); + } + + String nameanddesc = (name+sig); + if (method_names_and_desc.contains(nameanddesc)){ + throw new ClassConstraintException("No two methods (like '"+tostring(obj)+"') are allowed have same names and desciptors!"); + } + method_names_and_desc.add(nameanddesc); + + Attribute[] atts = obj.getAttributes(); + int num_code_atts = 0; + for (int i=0; i= cplen)){ + throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(obj)+"'."); + } + Constant c = cp.getConstant(index); + + if (CONST_Long.isInstance(c) && field_type.equals(Type.LONG)){ + return; + } + if (CONST_Float.isInstance(c) && field_type.equals(Type.FLOAT)){ + return; + } + if (CONST_Double.isInstance(c) && field_type.equals(Type.DOUBLE)){ + return; + } + if (CONST_Integer.isInstance(c) && (field_type.equals(Type.INT) || field_type.equals(Type.SHORT) || field_type.equals(Type.CHAR) || field_type.equals(Type.BYTE) || field_type.equals(Type.BOOLEAN))){ + return; + } + if (CONST_String.isInstance(c) && field_type.equals(Type.STRING)){ + return; + } + + throw new ClassConstraintException("Illegal type of ConstantValue '"+obj+"' embedding Constant '"+c+"'. It is referenced by field '"+tostring(f)+"' expecting a different type: '"+field_type+"'."); + } + } + // SYNTHETIC: see above + // DEPRECATED: see above + ///////////////////////////////////////////////////////// + // method_info-structure-ATTRIBUTES (vmspec2 4.6, 4.7) // + ///////////////////////////////////////////////////////// + public void visitCode(Code obj){//vmspec2 4.7.3 + try { + // No code attribute allowed for native or abstract methods: see visitMethod(Method). + // Code array constraints are checked in Pass3 (3a and 3b). + + checkIndex(obj, obj.getNameIndex(), CONST_Utf8); + + String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); + if (! name.equals("Code")){ + throw new ClassConstraintException("The Code attribute '"+tostring(obj)+"' is not correctly named 'Code' but '"+name+"'."); + } + + Method m = null; // satisfy compiler + if (!(carrier.predecessor() instanceof Method)){ + addMessage("Code attribute '"+tostring(obj)+"' is not declared in a method_info structure but in '"+carrier.predecessor()+"'. Ignored."); + return; + } + else{ + m = (Method) carrier.predecessor(); // we can assume this method was visited before; + // i.e. the data consistency was verified. + } + + if (obj.getCode().length == 0){ + throw new ClassConstraintException("Code array of Code attribute '"+tostring(obj)+"' (method '"+m+"') must not be empty."); + } + + //In JustIce, the check for correct offsets into the code array is delayed to Pass 3a. + CodeException[] exc_table = obj.getExceptionTable(); + for (int i=0; i= code.getMaxLocals()){ + throw new ClassConstraintException("LocalVariableTable attribute '"+tostring(lvt)+"' references a LocalVariable '"+tostring(localvariables[i])+"' with an index that exceeds the surrounding Code attribute's max_locals value of '"+code.getMaxLocals()+"'."); + } + + try{ + localVariablesInfos[method_number].add(localindex, localname, localvariables[i].getStartPC(), localvariables[i].getLength(), t); + } + catch(LocalVariableInfoInconsistentException lviie){ + throw new ClassConstraintException("Conflicting information in LocalVariableTable '"+tostring(lvt)+"' found in Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"'). "+lviie.getMessage()); + } + }// for all local variables localvariables[i] in the LocalVariableTable attribute atts[a] END + + num_of_lvt_attribs++; + if (num_of_lvt_attribs > obj.getMaxLocals()){ + throw new ClassConstraintException("Number of LocalVariableTable attributes of Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"') exceeds number of local variable slots '"+obj.getMaxLocals()+"' ('There may be no more than one LocalVariableTable attribute per local variable in the Code attribute.')."); + } + }// if atts[a] instanceof LocalVariableTable END + }// for all attributes atts[a] END + + } catch (ClassNotFoundException e) { + // FIXME: this might not be the best way to handle missing classes. + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + + }// visitCode(Code) END + + public void visitExceptionTable(ExceptionTable obj){//vmspec2 4.7.4 + try { + // incorrectly named, it's the Exceptions attribute (vmspec2 4.7.4) + checkIndex(obj, obj.getNameIndex(), CONST_Utf8); + + String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); + if (! name.equals("Exceptions")){ + throw new ClassConstraintException("The Exceptions attribute '"+tostring(obj)+"' is not correctly named 'Exceptions' but '"+name+"'."); + } + + int[] exc_indices = obj.getExceptionIndexTable(); + + for (int i=0; iPrecondition: index-style cross referencing in the constant + * pool must be valid. Simply invoke constant_pool_entries_satisfy_static_constraints() + * before. + * + * @throws ClassConstraintException otherwise. + * @see #constant_pool_entries_satisfy_static_constraints() + */ + private void field_and_method_refs_are_valid(){ + try { + JavaClass jc = Repository.lookupClass(myOwner.getClassName()); + DescendingVisitor v = new DescendingVisitor(jc, new FAMRAV_Visitor(jc)); + v.visit(); + + } catch (ClassNotFoundException e) { + // FIXME: this might not be the best way to handle missing classes. + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** + * A Visitor class that ensures the ConstantCP-subclassed entries + * of the constant pool are valid. + * Precondition: index-style cross referencing in the constant + * pool must be valid. + * + * @see #constant_pool_entries_satisfy_static_constraints() + * @see org.apache.bcel.classfile.ConstantCP + */ + private class FAMRAV_Visitor extends EmptyVisitor implements Visitor{ + private final ConstantPool cp; // ==jc.getConstantPool() -- only here to save typing work. + private FAMRAV_Visitor(JavaClass _jc){ + cp = _jc.getConstantPool(); + } + + public void visitConstantFieldref(ConstantFieldref obj){ + if (obj.getTag() != Constants.CONSTANT_Fieldref){ + throw new ClassConstraintException("ConstantFieldref '"+tostring(obj)+"' has wrong tag!"); + } + int name_and_type_index = obj.getNameAndTypeIndex(); + ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); + String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); // Field or Method name + if (!validFieldName(name)){ + throw new ClassConstraintException("Invalid field name '"+name+"' referenced by '"+tostring(obj)+"'."); + } + + int class_index = obj.getClassIndex(); + ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); + String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); // Class Name in internal form + if (! validClassName(className)){ + throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); + } + + String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor) + + try{ + Type.getType(sig); /* Don't need the return value */ + } + catch (ClassFormatException cfe){ + throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); + } + } + + public void visitConstantMethodref(ConstantMethodref obj){ + if (obj.getTag() != Constants.CONSTANT_Methodref){ + throw new ClassConstraintException("ConstantMethodref '"+tostring(obj)+"' has wrong tag!"); + } + int name_and_type_index = obj.getNameAndTypeIndex(); + ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); + String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); // Field or Method name + if (!validClassMethodName(name)){ + throw new ClassConstraintException("Invalid (non-interface) method name '"+name+"' referenced by '"+tostring(obj)+"'."); + } + + int class_index = obj.getClassIndex(); + ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); + String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); // Class Name in internal form + if (! validClassName(className)){ + throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); + } + + String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor) + + try{ + Type t = Type.getReturnType(sig); + if ( name.equals(CONSTRUCTOR_NAME) && (t != Type.VOID) ){ + throw new ClassConstraintException("Instance initialization method must have VOID return type."); + } + } + catch (ClassFormatException cfe){ + throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); + } + } + + public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){ + if (obj.getTag() != Constants.CONSTANT_InterfaceMethodref){ + throw new ClassConstraintException("ConstantInterfaceMethodref '"+tostring(obj)+"' has wrong tag!"); + } + int name_and_type_index = obj.getNameAndTypeIndex(); + ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); + String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); // Field or Method name + if (!validInterfaceMethodName(name)){ + throw new ClassConstraintException("Invalid (interface) method name '"+name+"' referenced by '"+tostring(obj)+"'."); + } + + int class_index = obj.getClassIndex(); + ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); + String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); // Class Name in internal form + if (! validClassName(className)){ + throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); + } + + String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor) + + try{ + Type t = Type.getReturnType(sig); + if ( name.equals(STATIC_INITIALIZER_NAME) && (t != Type.VOID) ){ + addMessage("Class or interface initialization method '"+STATIC_INITIALIZER_NAME+"' usually has VOID return type instead of '"+t+"'. Note this is really not a requirement of The Java Virtual Machine Specification, Second Edition."); + } + } + catch (ClassFormatException cfe){ + throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); + } + + } + + } + + /** + * This method returns true if and only if the supplied String + * represents a valid Java class name. + */ + private static final boolean validClassName(String name){ + /* + * TODO: implement. + * Are there any restrictions? + */ + return true; + } + /** + * This method returns true if and only if the supplied String + * represents a valid method name. + * This is basically the same as a valid identifier name in the + * Java programming language, but the special name for + * the instance initialization method is allowed and the special name + * for the class/interface initialization method may be allowed. + */ + private static boolean validMethodName(String name, boolean allowStaticInit){ + if (validJavaLangMethodName(name)) { + return true; + } + + if (allowStaticInit){ + return (name.equals(CONSTRUCTOR_NAME) || name.equals(STATIC_INITIALIZER_NAME)); + } + else{ + return name.equals(CONSTRUCTOR_NAME); + } + } + + /** + * This method returns true if and only if the supplied String + * represents a valid method name that may be referenced by + * ConstantMethodref objects. + */ + private static boolean validClassMethodName(String name){ + return validMethodName(name, false); + } + + /** + * This method returns true if and only if the supplied String + * represents a valid Java programming language method name stored as a simple + * (non-qualified) name. + * Conforming to: The Java Virtual Machine Specification, Second Edition, 2.7, 2.7.1, 2.2. + */ + private static boolean validJavaLangMethodName(String name){ + if (!Character.isJavaIdentifierStart(name.charAt(0))) { + return false; + } + + for (int i=1; i, thanks! + } + + // vmspec2 2.7, vmspec2 2.2 + if (!Character.isJavaIdentifierStart(name.charAt(0))) { + return false; + } + + for (int i=1; i= methods.length){ + throw new InvalidMethodException("METHOD DOES NOT EXIST!"); + } + Method method = methods[method_no]; + code = method.getCode(); + + // No Code? Nothing to verify! + if ( method.isAbstract() || method.isNative() ){ // IF mg HAS NO CODE (static constraint of Pass 2) + return VerificationResult.VR_OK; + } + + // TODO: + // We want a very sophisticated code examination here with good explanations + // on where to look for an illegal instruction or such. + // Only after that we should try to build an InstructionList and throw an + // AssertionViolatedException if after our examination InstructionList building + // still fails. + // That examination should be implemented in a byte-oriented way, i.e. look for + // an instruction, make sure its validity, count its length, find the next + // instruction and so on. + try{ + instructionList = new InstructionList(method.getCode().getCode()); + } + catch(RuntimeException re){ + return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Bad bytecode in the code array of the Code attribute of method '"+method+"'."); + } + + instructionList.setPositions(true); + + // Start verification. + VerificationResult vr = VerificationResult.VR_OK; //default + try{ + delayedPass2Checks(); + } + catch(ClassConstraintException cce){ + vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage()); + return vr; + } + try{ + pass3StaticInstructionChecks(); + pass3StaticInstructionOperandsChecks(); + } + catch(StaticCodeConstraintException scce){ + vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, scce.getMessage()); + } + catch(ClassCastException cce){ + vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Class Cast Exception: " + cce.getMessage()); + } + return vr; + } + else{ //did not pass Pass 2. + return VerificationResult.VR_NOTYET; + } + } catch (ClassNotFoundException e) { + // FIXME: maybe not the best way to handle this + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** + * These are the checks that could be done in pass 2 but are delayed to pass 3 + * for performance reasons. Also, these checks need access to the code array + * of the Code attribute of a Method so it's okay to perform them here. + * Also see the description of the do_verify() method. + * + * @throws ClassConstraintException if the verification fails. + * @see #do_verify() + */ + private void delayedPass2Checks(){ + + int[] instructionPositions = instructionList.getInstructionPositions(); + int codeLength = code.getCode().length; + + ///////////////////// + // LineNumberTable // + ///////////////////// + LineNumberTable lnt = code.getLineNumberTable(); + if (lnt != null){ + LineNumber[] lineNumbers = lnt.getLineNumberTable(); + IntList offsets = new IntList(); + lineNumber_loop: for (int i=0; i < lineNumbers.length; i++){ // may appear in any order. + for (int j=0; j < instructionPositions.length; j++){ + // TODO: Make this a binary search! The instructionPositions array is naturally ordered! + int offset = lineNumbers[i].getStartPC(); + if (instructionPositions[j] == offset){ + if (offsets.contains(offset)){ + addMessage("LineNumberTable attribute '"+code.getLineNumberTable()+"' refers to the same code offset ('"+offset+"') more than once which is violating the semantics [but is sometimes produced by IBM's 'jikes' compiler]."); + } + else{ + offsets.add(offset); + } + continue lineNumber_loop; + } + } + throw new ClassConstraintException("Code attribute '"+code+"' has a LineNumberTable attribute '"+code.getLineNumberTable()+"' referring to a code offset ('"+lineNumbers[i].getStartPC()+"') that does not exist."); + } + } + + /////////////////////////// + // LocalVariableTable(s) // + /////////////////////////// + /* We cannot use code.getLocalVariableTable() because there could be more + than only one. This is a bug in BCEL. */ + Attribute[] atts = code.getAttributes(); + for (int a=0; a= endpc){ + throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has its start_pc ('"+startpc+"') not smaller than its end_pc ('"+endpc+"')."); + } + if (!contains(instructionPositions, startpc)){ + throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its start_pc ('"+startpc+"')."); + } + if ( (!contains(instructionPositions, endpc)) && (endpc != codeLength)){ + throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its end_pc ('"+startpc+"') [that is also not equal to code_length ('"+codeLength+"')]."); + } + if (!contains(instructionPositions, handlerpc)){ + throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its handler_pc ('"+handlerpc+"')."); + } + } + } + + /** + * These are the checks if constraints are satisfied which are described in the + * Java Virtual Machine Specification, Second Edition as Static Constraints on + * the instructions of Java Virtual Machine Code (chapter 4.8.1). + * + * @throws StaticCodeConstraintException if the verification fails. + */ + private void pass3StaticInstructionChecks(){ + + // Code array must not be empty: + // Enforced in pass 2 (also stated in the static constraints of the Code + // array in vmspec2), together with pass 1 (reading code_length bytes and + // interpreting them as code[]). So this must not be checked again here. + + if (! (code.getCode().length < 65536)){// contradicts vmspec2 page 152 ("Limitations"), but is on page 134. + throw new StaticCodeInstructionConstraintException("Code array in code attribute '"+code+"' too big: must be smaller than 65536 bytes."); + } + + // First opcode at offset 0: okay, that's clear. Nothing to do. + + // Only instances of the instructions documented in Section 6.4 may appear in + // the code array. + + // For BCEL's sake, we cannot handle WIDE stuff, but hopefully BCEL does its job right :) + + // The last byte of the last instruction in the code array must be the byte at index + // code_length-1 : See the do_verify() comments. We actually don't iterate through the + // byte array, but use an InstructionList so we cannot check for this. But BCEL does + // things right, so it's implicitly okay. + + // TODO: Check how BCEL handles (and will handle) instructions like IMPDEP1, IMPDEP2, + // BREAKPOINT... that BCEL knows about but which are illegal anyway. + // We currently go the safe way here. + InstructionHandle ih = instructionList.getStart(); + while (ih != null){ + Instruction i = ih.getInstruction(); + if (i instanceof IMPDEP1){ + throw new StaticCodeInstructionConstraintException("IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!"); + } + if (i instanceof IMPDEP2){ + throw new StaticCodeInstructionConstraintException("IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!"); + } + if (i instanceof BREAKPOINT){ + throw new StaticCodeInstructionConstraintException("BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!"); + } + ih = ih.getNext(); + } + + // The original verifier seems to do this check here, too. + // An unreachable last instruction may also not fall through the + // end of the code, which is stupid -- but with the original + // verifier's subroutine semantics one cannot predict reachability. + Instruction last = instructionList.getEnd().getInstruction(); + if (! ((last instanceof ReturnInstruction) || + (last instanceof RET) || + (last instanceof GotoInstruction) || + (last instanceof ATHROW) )) { + throw new StaticCodeInstructionConstraintException("Execution must not fall off the bottom of the code array. This constraint is enforced statically as some existing verifiers do - so it may be a false alarm if the last instruction is not reachable."); + } + } + + /** + * These are the checks for the satisfaction of constraints which are described in the + * Java Virtual Machine Specification, Second Edition as Static Constraints on + * the operands of instructions of Java Virtual Machine Code (chapter 4.8.1). + * BCEL parses the code array to create an InstructionList and therefore has to check + * some of these constraints. Additional checks are also implemented here. + * + * @throws StaticCodeConstraintException if the verification fails. + */ + private void pass3StaticInstructionOperandsChecks(){ + try { + // When building up the InstructionList, BCEL has already done all those checks + // mentioned in The Java Virtual Machine Specification, Second Edition, as + // "static constraints on the operands of instructions in the code array". + // TODO: see the do_verify() comments. Maybe we should really work on the + // byte array first to give more comprehensive messages. + // TODO: Review Exception API, possibly build in some "offending instruction" thing + // when we're ready to insulate the offending instruction by doing the + // above thing. + + // TODO: Implement as much as possible here. BCEL does _not_ check everything. + + ConstantPoolGen cpg = new ConstantPoolGen(Repository.lookupClass(myOwner.getClassName()).getConstantPool()); + InstOperandConstraintVisitor v = new InstOperandConstraintVisitor(cpg); + + // Checks for the things BCEL does _not_ handle itself. + InstructionHandle ih = instructionList.getStart(); + while (ih != null){ + Instruction i = ih.getInstruction(); + + // An "own" constraint, due to JustIce's new definition of what "subroutine" means. + if (i instanceof JsrInstruction){ + InstructionHandle target = ((JsrInstruction) i).getTarget(); + if (target == instructionList.getStart()){ + throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may have a top-level instruction (such as the very first instruction, which is targeted by instruction '"+ih+"' as its target."); + } + if (!(target.getInstruction() instanceof ASTORE)){ + throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may target anything else than an ASTORE instruction. Instruction '"+ih+"' targets '"+target+"'."); + } + } + + // vmspec2, page 134-137 + ih.accept(v); + + ih = ih.getNext(); + } + + } catch (ClassNotFoundException e) { + // FIXME: maybe not the best way to handle this + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** A small utility method returning if a given int i is in the given int[] ints. */ + private static boolean contains(int[] ints, int i){ + for (int j=0; j= cpg.getSize()){ + constraintViolated(i, "Illegal constant pool index '"+idx+"'."); + } + } + + /////////////////////////////////////////////////////////// + // The Java Virtual Machine Specification, pages 134-137 // + /////////////////////////////////////////////////////////// + /** + * Assures the generic preconditions of a LoadClass instance. + * The referenced class is loaded and pass2-verified. + */ + public void visitLoadClass(LoadClass o){ + ObjectType t = o.getLoadClassType(cpg); + if (t != null){// null means "no class is loaded" + Verifier v = VerifierFactory.getVerifier(t.getClassName()); + VerificationResult vr = v.doPass1(); + if (vr.getStatus() != VerificationResult.VERIFIED_OK){ + constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded: '"+vr+"'."); + } + } + } + + // The target of each jump and branch instruction [...] must be the opcode [...] + // BCEL _DOES_ handle this. + + // tableswitch: BCEL will do it, supposedly. + + // lookupswitch: BCEL will do it, supposedly. + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + // LDC and LDC_W (LDC_W is a subclass of LDC in BCEL's model) + public void visitLDC(LDC o){ + indexValid(o, o.getIndex()); + Constant c = cpg.getConstant(o.getIndex()); + if (c instanceof ConstantClass){ + addMessage("Operand of LDC or LDC_W is CONSTANT_Class '"+c+"' - this is only supported in JDK 1.5 and higher."); + } + else{ + if (! ( (c instanceof ConstantInteger) || + (c instanceof ConstantFloat) || + (c instanceof ConstantString) ) ){ + constraintViolated(o, "Operand of LDC or LDC_W must be one of CONSTANT_Integer, CONSTANT_Float or CONSTANT_String, but is '"+c+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + // LDC2_W + public void visitLDC2_W(LDC2_W o){ + indexValid(o, o.getIndex()); + Constant c = cpg.getConstant(o.getIndex()); + if (! ( (c instanceof ConstantLong) || + (c instanceof ConstantDouble) ) ){ + constraintViolated(o, "Operand of LDC2_W must be CONSTANT_Long or CONSTANT_Double, but is '"+c+"'."); + } + try{ + indexValid(o, o.getIndex()+1); + } + catch(StaticCodeInstructionOperandConstraintException e){ + throw new AssertionViolatedException("OOPS: Does not BCEL handle that? LDC2_W operand has a problem."); + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + //getfield, putfield, getstatic, putstatic + public void visitFieldInstruction(FieldInstruction o){ + try { + indexValid(o, o.getIndex()); + Constant c = cpg.getConstant(o.getIndex()); + if (! (c instanceof ConstantFieldref)){ + constraintViolated(o, "Indexing a constant that's not a CONSTANT_Fieldref but a '"+c+"'."); + } + + String field_name = o.getFieldName(cpg); + + JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName()); + Field[] fields = jc.getFields(); + Field f = null; + for (int i=0; i or + ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantInterfaceMethodref)c).getNameAndTypeIndex())); + String name = ((ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()))).getBytes(); + if (name.equals(Constants.CONSTRUCTOR_NAME)){ + constraintViolated(o, "Method to invoke must not be '"+Constants.CONSTRUCTOR_NAME+"'."); + } + if (name.equals(Constants.STATIC_INITIALIZER_NAME)){ + constraintViolated(o, "Method to invoke must not be '"+Constants.STATIC_INITIALIZER_NAME+"'."); + } + } + + // The LoadClassType is the method-declaring class, so we have to check the other types. + + Type t = o.getReturnType(cpg); + if (t instanceof ArrayType){ + t = ((ArrayType) t).getBasicType(); + } + if (t instanceof ObjectType){ + Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName()); + VerificationResult vr = v.doPass2(); + if (vr.getStatus() != VerificationResult.VERIFIED_OK){ + constraintViolated(o, "Return type class/interface could not be verified successfully: '"+vr.getMessage()+"'."); + } + } + + Type[] ts = o.getArgumentTypes(cpg); + for (int i=0; i= 255){ + constraintViolated(o, "Not allowed to create an array with more than 255 dimensions."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitNEWARRAY(NEWARRAY o){ + byte t = o.getTypecode(); + if (! ( (t == Constants.T_BOOLEAN) || + (t == Constants.T_CHAR) || + (t == Constants.T_FLOAT) || + (t == Constants.T_DOUBLE) || + (t == Constants.T_BYTE) || + (t == Constants.T_SHORT) || + (t == Constants.T_INT) || + (t == Constants.T_LONG) ) ){ + constraintViolated(o, "Illegal type code '+t+' for 'atype' operand."); + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitILOAD(ILOAD o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative."); + } + else{ + int maxminus1 = max_locals()-1; + if (idx > maxminus1){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitFLOAD(FLOAD o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative."); + } + else{ + int maxminus1 = max_locals()-1; + if (idx > maxminus1){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitALOAD(ALOAD o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative."); + } + else{ + int maxminus1 = max_locals()-1; + if (idx > maxminus1){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitISTORE(ISTORE o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative."); + } + else{ + int maxminus1 = max_locals()-1; + if (idx > maxminus1){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitFSTORE(FSTORE o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative."); + } + else{ + int maxminus1 = max_locals()-1; + if (idx > maxminus1){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitASTORE(ASTORE o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative."); + } + else{ + int maxminus1 = max_locals()-1; + if (idx > maxminus1){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitIINC(IINC o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative."); + } + else{ + int maxminus1 = max_locals()-1; + if (idx > maxminus1){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitRET(RET o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative."); + } + else{ + int maxminus1 = max_locals()-1; + if (idx > maxminus1){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitLLOAD(LLOAD o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]"); + } + else{ + int maxminus2 = max_locals()-2; + if (idx > maxminus2){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitDLOAD(DLOAD o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]"); + } + else{ + int maxminus2 = max_locals()-2; + if (idx > maxminus2){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitLSTORE(LSTORE o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]"); + } + else{ + int maxminus2 = max_locals()-2; + if (idx > maxminus2){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitDSTORE(DSTORE o){ + int idx = o.getIndex(); + if (idx < 0){ + constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]"); + } + else{ + int maxminus2 = max_locals()-2; + if (idx > maxminus2){ + constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'."); + } + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitLOOKUPSWITCH(LOOKUPSWITCH o){ + int[] matchs = o.getMatchs(); + int max = Integer.MIN_VALUE; + for (int i=0; i= "low". We cannot check this, as BCEL hides + // it from us. + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitPUTSTATIC(PUTSTATIC o){ + try { + String field_name = o.getFieldName(cpg); + JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName()); + Field[] fields = jc.getFields(); + Field f = null; + for (int i=0; i. + if ((!(jc.isClass())) && (!(meth_name.equals(Constants.STATIC_INITIALIZER_NAME)))){ + constraintViolated(o, "Interface field '"+f+"' must be set in a '"+Constants.STATIC_INITIALIZER_NAME+"' method."); + } + } catch (ClassNotFoundException e) { + // FIXME: maybe not the best way to handle this + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** Checks if the constraints of operands of the said instruction(s) are satisfied. */ + public void visitGETSTATIC(GETSTATIC o){ + try { + String field_name = o.getFieldName(cpg); + JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName()); + Field[] fields = jc.getFields(); + Field f = null; + for (int i=0; iaccept() Visitor + * instances) have toString() methods that were not designed to be robust, + * this gap is closed by this class. + * When performing class file verification, it may be useful to output which + * entity (e.g. a Code instance) is not satisfying the verifier's + * constraints, but in this case it could be possible for the toString() + * method to throw a RuntimeException. + * A (new StringRepresentation(Node n)).toString() never throws any exception. + * Note that this class also serves as a placeholder for more sophisticated message + * handling in future versions of JustIce. + * + * @version $Id: StringRepresentation.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public class StringRepresentation extends org.apache.bcel.classfile.EmptyVisitor implements Visitor { + /** The string representation, created by a visitXXX() method, output by toString(). */ + private String tostring; + /** The node we ask for its string representation. Not really needed; only for debug output. */ + private Node n; + + /** + * Creates a new StringRepresentation object which is the representation of n. + * + * @see #toString() + */ + public StringRepresentation(Node n) { + this.n = n; + n.accept(this); // assign a string representation to field 'tostring' if we know n's class. + } + + /** + * Returns the String representation. + */ + public String toString() { +// The run-time check below is needed because we don't want to omit inheritance +// of "EmptyVisitor" and provide a thousand empty methods. +// However, in terms of performance this would be a better idea. +// If some new "Node" is defined in BCEL (such as some concrete "Attribute"), we +// want to know that this class has also to be adapted. + if (tostring == null) { + throw new AssertionViolatedException("Please adapt '" + getClass() + "' to deal with objects of class '" + n.getClass() + "'."); + } + return tostring; + } + + /** + * Returns the String representation of the Node object obj; + * this is obj.toString() if it does not throw any RuntimeException, + * or else it is a string derived only from obj's class name. + */ + private String toString(Node obj) { + String ret; + try { + ret = obj.toString(); + } + catch (RuntimeException e) { // including ClassFormatException, trying to convert the "signature" of a ReturnaddressType LocalVariable (shouldn't occur, but people do crazy things) + String s = obj.getClass().getName(); + s = s.substring(s.lastIndexOf(".") + 1); + ret = "<<" + s + ">>"; + } + return ret; + } + + //////////////////////////////// + // Visitor methods start here // + //////////////////////////////// + // We don't of course need to call some default implementation: + // e.g. we could also simply output "Code" instead of a possibly + // lengthy Code attribute's toString(). + public void visitCode(Code obj) { + //tostring = toString(obj); + tostring = ""; // We don't need real code outputs. + } + + public void visitCodeException(CodeException obj) { + tostring = toString(obj); + } + + public void visitConstantClass(ConstantClass obj) { + tostring = toString(obj); + } + + public void visitConstantDouble(ConstantDouble obj) { + tostring = toString(obj); + } + + public void visitConstantFieldref(ConstantFieldref obj) { + tostring = toString(obj); + } + + public void visitConstantFloat(ConstantFloat obj) { + tostring = toString(obj); + } + + public void visitConstantInteger(ConstantInteger obj) { + tostring = toString(obj); + } + + public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj) { + tostring = toString(obj); + } + + public void visitConstantLong(ConstantLong obj) { + tostring = toString(obj); + } + + public void visitConstantMethodref(ConstantMethodref obj) { + tostring = toString(obj); + } + + public void visitConstantNameAndType(ConstantNameAndType obj) { + tostring = toString(obj); + } + + public void visitConstantPool(ConstantPool obj) { + tostring = toString(obj); + } + + public void visitConstantString(ConstantString obj) { + tostring = toString(obj); + } + + public void visitConstantUtf8(ConstantUtf8 obj) { + tostring = toString(obj); + } + + public void visitConstantValue(ConstantValue obj) { + tostring = toString(obj); + } + + public void visitDeprecated(Deprecated obj) { + tostring = toString(obj); + } + + public void visitExceptionTable(ExceptionTable obj) { + tostring = toString(obj); + } + + public void visitField(Field obj) { + tostring = toString(obj); + } + + public void visitInnerClass(InnerClass obj) { + tostring = toString(obj); + } + + public void visitInnerClasses(InnerClasses obj) { + tostring = toString(obj); + } + + public void visitJavaClass(JavaClass obj) { + tostring = toString(obj); + } + + public void visitLineNumber(LineNumber obj) { + tostring = toString(obj); + } + + public void visitLineNumberTable(LineNumberTable obj) { + tostring = ""; + } + + public void visitLocalVariable(LocalVariable obj) { + tostring = toString(obj); + } + + public void visitLocalVariableTable(LocalVariableTable obj) { + tostring = ""; + } + + public void visitMethod(Method obj) { + tostring = toString(obj); + } + + public void visitSignature(Signature obj) { + tostring = toString(obj); + } + + public void visitSourceFile(SourceFile obj) { + tostring = toString(obj); + } + + public void visitStackMap(StackMap obj) { + tostring = toString(obj); + } + + public void visitSynthetic(Synthetic obj) { + tostring = toString(obj); + } + + public void visitUnknown(Unknown obj) { + tostring = toString(obj); + } +} diff --git a/src/org/apache/bcel/verifier/statics/package.html b/src/org/apache/bcel/verifier/statics/package.html new file mode 100644 index 0000000..e805897 --- /dev/null +++ b/src/org/apache/bcel/verifier/statics/package.html @@ -0,0 +1,19 @@ + + + + + + + +Provides PassVerifier classes used internally by JustIce. You don't need to bother with them. + +

      Package Specification

      + +Contained in this package are PassVerifier classes for use with the JustIce verifier. +Only the passes performing what Sun calls 'static constraints' have PassVerifier classes +here. + + + diff --git a/src/org/apache/bcel/verifier/structurals/ControlFlowGraph.java b/src/org/apache/bcel/verifier/structurals/ControlFlowGraph.java new file mode 100644 index 0000000..93c6405 --- /dev/null +++ b/src/org/apache/bcel/verifier/structurals/ControlFlowGraph.java @@ -0,0 +1,460 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.structurals; + + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Map; +import org.apache.bcel.generic.ATHROW; +import org.apache.bcel.generic.BranchInstruction; +import org.apache.bcel.generic.GotoInstruction; +import org.apache.bcel.generic.Instruction; +import org.apache.bcel.generic.InstructionHandle; +import org.apache.bcel.generic.JsrInstruction; +import org.apache.bcel.generic.MethodGen; +import org.apache.bcel.generic.RET; +import org.apache.bcel.generic.ReturnInstruction; +import org.apache.bcel.generic.Select; +import org.apache.bcel.verifier.exc.AssertionViolatedException; +import org.apache.bcel.verifier.exc.StructuralCodeConstraintException; + +/** + * This class represents a control flow graph of a method. + * + * @version $Id: ControlFlowGraph.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public class ControlFlowGraph{ + + /** + * Objects of this class represent a node in a ControlFlowGraph. + * These nodes are instructions, not basic blocks. + */ + private class InstructionContextImpl implements InstructionContext{ + + /** + * The TAG field is here for external temporary flagging, such + * as graph colouring. + * + * @see #getTag() + * @see #setTag(int) + */ + private int TAG; + + /** + * The InstructionHandle this InstructionContext is wrapped around. + */ + private InstructionHandle instruction; + + /** + * The 'incoming' execution Frames. + */ + private Map inFrames; // key: the last-executed JSR + + /** + * The 'outgoing' execution Frames. + */ + private Map outFrames; // key: the last-executed JSR + + /** + * The 'execution predecessors' - a list of type InstructionContext + * of those instances that have been execute()d before in that order. + */ + private ArrayList executionPredecessors = null; // Type: InstructionContext + + /** + * Creates an InstructionHandleImpl object from an InstructionHandle. + * Creation of one per InstructionHandle suffices. Don't create more. + */ + public InstructionContextImpl(InstructionHandle inst){ + if (inst == null) { + throw new AssertionViolatedException("Cannot instantiate InstructionContextImpl from NULL."); + } + + instruction = inst; + inFrames = new java.util.HashMap(); + outFrames = new java.util.HashMap(); + } + + /* Satisfies InstructionContext.getTag(). */ + public int getTag(){ + return TAG; + } + + /* Satisfies InstructionContext.setTag(int). */ + public void setTag(int tag){ + TAG = tag; + } + + /** + * Returns the exception handlers of this instruction. + */ + public ExceptionHandler[] getExceptionHandlers(){ + return exceptionhandlers.getExceptionHandlers(getInstruction()); + } + + /** + * Returns a clone of the "outgoing" frame situation with respect to the given ExecutionChain. + */ + public Frame getOutFrame(ArrayList execChain){ + executionPredecessors = execChain; + + Frame org; + + InstructionContext jsr = lastExecutionJSR(); + + org = (Frame) outFrames.get(jsr); + + if (org == null){ + throw new AssertionViolatedException("outFrame not set! This:\n"+this+"\nExecutionChain: "+getExecutionChain()+"\nOutFrames: '"+outFrames+"'."); + } + return org.getClone(); + } + + public Frame getInFrame() { + Frame org; + + InstructionContext jsr = lastExecutionJSR(); + + org = (Frame) inFrames.get(jsr); + + if (org == null){ + throw new AssertionViolatedException("inFrame not set! This:\n"+this+"\nInFrames: '"+inFrames+"'."); + } + return org.getClone(); + } + + /** + * "Merges in" (vmspec2, page 146) the "incoming" frame situation; + * executes the instructions symbolically + * and therefore calculates the "outgoing" frame situation. + * Returns: True iff the "incoming" frame situation changed after + * merging with "inFrame". + * The execPreds ArrayList must contain the InstructionContext + * objects executed so far in the correct order. This is just + * one execution path [out of many]. This is needed to correctly + * "merge" in the special case of a RET's successor. + * The InstConstraintVisitor and ExecutionVisitor instances + * must be set up correctly. + * @return true - if and only if the "outgoing" frame situation + * changed from the one before execute()ing. + */ + public boolean execute(Frame inFrame, ArrayList execPreds, InstConstraintVisitor icv, ExecutionVisitor ev){ + + executionPredecessors = (ArrayList) execPreds.clone(); + + //sanity check + if ( (lastExecutionJSR() == null) && (subroutines.subroutineOf(getInstruction()) != subroutines.getTopLevel() ) ){ + throw new AssertionViolatedException("Huh?! Am I '"+this+"' part of a subroutine or not?"); + } + if ( (lastExecutionJSR() != null) && (subroutines.subroutineOf(getInstruction()) == subroutines.getTopLevel() ) ){ + throw new AssertionViolatedException("Huh?! Am I '"+this+"' part of a subroutine or not?"); + } + + Frame inF = (Frame) inFrames.get(lastExecutionJSR()); + if (inF == null){// no incoming frame was set, so set it. + inFrames.put(lastExecutionJSR(), inFrame); + inF = inFrame; + } + else{// if there was an "old" inFrame + if (inF.equals(inFrame)){ //shortcut: no need to merge equal frames. + return false; + } + if (! mergeInFrames(inFrame)){ + return false; + } + } + + // Now we're sure the inFrame has changed! + + // new inFrame is already merged in, see above. + Frame workingFrame = inF.getClone(); + + try{ + // This verifies the InstructionConstraint for the current + // instruction, but does not modify the workingFrame object. +//InstConstraintVisitor icv = InstConstraintVisitor.getInstance(VerifierFactory.getVerifier(method_gen.getClassName())); + icv.setFrame(workingFrame); + getInstruction().accept(icv); + } + catch(StructuralCodeConstraintException ce){ + ce.extendMessage("","\nInstructionHandle: "+getInstruction()+"\n"); + ce.extendMessage("","\nExecution Frame:\n"+workingFrame); + extendMessageWithFlow(ce); + throw ce; + } + + // This executes the Instruction. + // Therefore the workingFrame object is modified. +//ExecutionVisitor ev = ExecutionVisitor.getInstance(VerifierFactory.getVerifier(method_gen.getClassName())); + ev.setFrame(workingFrame); + getInstruction().accept(ev); + //getInstruction().accept(ExecutionVisitor.withFrame(workingFrame)); + outFrames.put(lastExecutionJSR(), workingFrame); + + return true; // new inFrame was different from old inFrame so merging them + // yielded a different this.inFrame. + } + + /** + * Returns a simple String representation of this InstructionContext. + */ + public String toString(){ + //TODO: Put information in the brackets, e.g. + // Is this an ExceptionHandler? Is this a RET? Is this the start of + // a subroutine? + String ret = getInstruction().toString(false)+"\t[InstructionContext]"; + return ret; + } + + /** + * Does the actual merging (vmspec2, page 146). + * Returns true IFF this.inFrame was changed in course of merging with inFrame. + */ + private boolean mergeInFrames(Frame inFrame){ + // TODO: Can be performance-improved. + Frame inF = (Frame) inFrames.get(lastExecutionJSR()); + OperandStack oldstack = inF.getStack().getClone(); + LocalVariables oldlocals = inF.getLocals().getClone(); + try{ + inF.getStack().merge(inFrame.getStack()); + inF.getLocals().merge(inFrame.getLocals()); + } + catch (StructuralCodeConstraintException sce){ + extendMessageWithFlow(sce); + throw sce; + } + if ( oldstack.equals(inF.getStack()) && + oldlocals.equals(inF.getLocals()) ){ + return false; + } + else{ + return true; + } + } + + /** + * Returns the control flow execution chain. This is built + * while execute(Frame, ArrayList)-ing the code represented + * by the surrounding ControlFlowGraph. + */ + private String getExecutionChain(){ + String s = this.toString(); + for (int i=executionPredecessors.size()-1; i>=0; i--){ + s = executionPredecessors.get(i)+"\n" + s; + } + return s; + } + + + /** + * Extends the StructuralCodeConstraintException ("e") object with an at-the-end-extended message. + * This extended message will then reflect the execution flow needed to get to the constraint + * violation that triggered the throwing of the "e" object. + */ + private void extendMessageWithFlow(StructuralCodeConstraintException e){ + String s = "Execution flow:\n"; + e.extendMessage("", s+getExecutionChain()); + } + + /* + * Fulfils the contract of InstructionContext.getInstruction(). + */ + public InstructionHandle getInstruction(){ + return instruction; + } + + /** + * Returns the InstructionContextImpl with an JSR/JSR_W + * that was last in the ExecutionChain, without + * a corresponding RET, i.e. + * we were called by this one. + * Returns null if we were called from the top level. + */ + private InstructionContextImpl lastExecutionJSR(){ + + int size = executionPredecessors.size(); + int retcount = 0; + + for (int i=size-1; i>=0; i--){ + InstructionContextImpl current = (InstructionContextImpl) (executionPredecessors.get(i)); + Instruction currentlast = current.getInstruction().getInstruction(); + if (currentlast instanceof RET) { + retcount++; + } + if (currentlast instanceof JsrInstruction){ + retcount--; + if (retcount == -1) { + return current; + } + } + } + return null; + } + + /* Satisfies InstructionContext.getSuccessors(). */ + public InstructionContext[] getSuccessors(){ + return contextsOf(_getSuccessors()); + } + + /** + * A utility method that calculates the successors of a given InstructionHandle + * That means, a RET does have successors as defined here. + * A JsrInstruction has its target as its successor + * (opposed to its physical successor) as defined here. + */ +// TODO: implement caching! + private InstructionHandle[] _getSuccessors(){ + final InstructionHandle[] empty = new InstructionHandle[0]; + final InstructionHandle[] single = new InstructionHandle[1]; + final InstructionHandle[] pair = new InstructionHandle[2]; + + Instruction inst = getInstruction().getInstruction(); + + if (inst instanceof RET){ + Subroutine s = subroutines.subroutineOf(getInstruction()); + if (s==null){ //return empty; // RET in dead code. "empty" would be the correct answer, but we know something about the surrounding project... + throw new AssertionViolatedException("Asking for successors of a RET in dead code?!"); + } + +//TODO: remove. Only JustIce must not use it, but foreign users of the ControlFlowGraph +// will want it. Thanks Johannes Wust. +//throw new AssertionViolatedException("DID YOU REALLY WANT TO ASK FOR RET'S SUCCS?"); + + InstructionHandle[] jsrs = s.getEnteringJsrInstructions(); + InstructionHandle[] ret = new InstructionHandle[jsrs.length]; + for (int i=0; i(NOT ORDERED!). + */ + public InstructionContext[] getInstructionContexts(){ + InstructionContext[] ret = new InstructionContext[instructionContexts.values().size()]; + return (InstructionContext[]) instructionContexts.values().toArray(ret); + } + + /** + * Returns true, if and only if the said instruction is not reachable; that means, + * if it is not part of this ControlFlowGraph. + */ + public boolean isDead(InstructionHandle i){ + return subroutines.subroutineOf(i) == null; + } +} diff --git a/src/org/apache/bcel/verifier/structurals/ExceptionHandler.java b/src/org/apache/bcel/verifier/structurals/ExceptionHandler.java new file mode 100644 index 0000000..4f04d1d --- /dev/null +++ b/src/org/apache/bcel/verifier/structurals/ExceptionHandler.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.structurals; + + +import org.apache.bcel.generic.InstructionHandle; +import org.apache.bcel.generic.ObjectType; + +/** + * This class represents an exception handler; that is, an ObjectType + * representing a subclass of java.lang.Throwable and the instruction + * the handler starts off (represented by an InstructionContext). + * + * @version $Id: ExceptionHandler.java 371539 2006-01-23 14:08:00Z tcurdt $ + * @author Enver Haase + */ +public class ExceptionHandler{ + /** The type of the exception to catch. NULL means ANY. */ + private ObjectType catchtype; + + /** The InstructionHandle where the handling begins. */ + private InstructionHandle handlerpc; + + /** Leave instance creation to JustIce. */ + ExceptionHandler(ObjectType catch_type, InstructionHandle handler_pc){ + catchtype = catch_type; + handlerpc = handler_pc; + } + + /** + * Returns the type of the exception that's handled. 'null' means 'ANY'. + */ + public ObjectType getExceptionType(){ + return catchtype; + } + + /** + * Returns the InstructionHandle where the handler starts off. + */ + public InstructionHandle getHandlerStart(){ + return handlerpc; + } +} diff --git a/src/org/apache/bcel/verifier/structurals/ExceptionHandlers.java b/src/org/apache/bcel/verifier/structurals/ExceptionHandlers.java new file mode 100644 index 0000000..b847834 --- /dev/null +++ b/src/org/apache/bcel/verifier/structurals/ExceptionHandlers.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.structurals; + + +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; +import org.apache.bcel.generic.CodeExceptionGen; +import org.apache.bcel.generic.InstructionHandle; +import org.apache.bcel.generic.MethodGen; + +/** + * This class allows easy access to ExceptionHandler objects. + * + * @version $Id: ExceptionHandlers.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public class ExceptionHandlers{ + /** + * The ExceptionHandler instances. + * Key: InstructionHandle objects, Values: HashSet instances. + */ + private Hashtable exceptionhandlers; + + /** + * Constructor. Creates a new ExceptionHandlers instance. + */ + public ExceptionHandlers(MethodGen mg){ + exceptionhandlers = new Hashtable(); + CodeExceptionGen[] cegs = mg.getExceptionHandlers(); + for (int i=0; iConventions: + * + * Type.VOID will never be pushed onto the stack. Type.DOUBLE and Type.LONG + * that would normally take up two stack slots (like Double_HIGH and + * Double_LOW) are represented by a simple single Type.DOUBLE or Type.LONG + * object on the stack here. + * If a two-slot type is stored into a local variable, the next variable + * is given the type Type.UNKNOWN. + * + * @version $Id: ExecutionVisitor.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + * @see #visitDSTORE(DSTORE o) + * @see InstConstraintVisitor + */ +public class ExecutionVisitor extends EmptyVisitor implements Visitor{ + + /** + * The executionframe we're operating on. + */ + private Frame frame = null; + + /** + * The ConstantPoolGen we're working with. + * @see #setConstantPoolGen(ConstantPoolGen) + */ + private ConstantPoolGen cpg = null; + + /** + * Constructor. Constructs a new instance of this class. + */ + public ExecutionVisitor(){} + + /** + * The OperandStack from the current Frame we're operating on. + * @see #setFrame(Frame) + */ + private OperandStack stack(){ + return frame.getStack(); + } + + /** + * The LocalVariables from the current Frame we're operating on. + * @see #setFrame(Frame) + */ + private LocalVariables locals(){ + return frame.getLocals(); + } + + /** + * Sets the ConstantPoolGen needed for symbolic execution. + */ + public void setConstantPoolGen(ConstantPoolGen cpg){ + this.cpg = cpg; + } + + /** + * The only method granting access to the single instance of + * the ExecutionVisitor class. Before actively using this + * instance, SET THE ConstantPoolGen FIRST. + * @see #setConstantPoolGen(ConstantPoolGen) + */ + public void setFrame(Frame f){ + this.frame = f; + } + + ///** Symbolically executes the corresponding Java Virtual Machine instruction. */ + //public void visitWIDE(WIDE o){ + // The WIDE instruction is modelled as a flag + // of the embedded instructions in BCEL. + // Therefore BCEL checks for possible errors + // when parsing in the .class file: We don't + // have even the possibilty to care for WIDE + // here. + //} + + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitAALOAD(AALOAD o){ + stack().pop(); // pop the index int +//System.out.print(stack().peek()); + Type t = stack().pop(); // Pop Array type + if (t == Type.NULL){ + stack().push(Type.NULL); + } // Do nothing stackwise --- a NullPointerException is thrown at Run-Time + else{ + ArrayType at = (ArrayType) t; + stack().push(at.getElementType()); + } + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitAASTORE(AASTORE o){ + stack().pop(); + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitACONST_NULL(ACONST_NULL o){ + stack().push(Type.NULL); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitALOAD(ALOAD o){ + stack().push(locals().get(o.getIndex())); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitANEWARRAY(ANEWARRAY o){ + stack().pop(); //count + stack().push( new ArrayType(o.getType(cpg), 1) ); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitARETURN(ARETURN o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitARRAYLENGTH(ARRAYLENGTH o){ + stack().pop(); + stack().push(Type.INT); + } + + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitASTORE(ASTORE o){ + locals().set(o.getIndex(), stack().pop()); + //System.err.println("TODO-DEBUG: set LV '"+o.getIndex()+"' to '"+locals().get(o.getIndex())+"'."); + } + + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitATHROW(ATHROW o){ + Type t = stack().pop(); + stack().clear(); + if (t.equals(Type.NULL)) { + stack().push(Type.getType("Ljava/lang/NullPointerException;")); + } else { + stack().push(t); + } + } + + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitBALOAD(BALOAD o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitBASTORE(BASTORE o){ + stack().pop(); + stack().pop(); + stack().pop(); + } + + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitBIPUSH(BIPUSH o){ + stack().push(Type.INT); + } + + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitCALOAD(CALOAD o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitCASTORE(CASTORE o){ + stack().pop(); + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitCHECKCAST(CHECKCAST o){ + // It's possibly wrong to do so, but SUN's + // ByteCode verifier seems to do (only) this, too. + // TODO: One could use a sophisticated analysis here to check + // if a type cannot possibly be cated to another and by + // so doing predict the ClassCastException at run-time. + stack().pop(); + stack().push(o.getType(cpg)); + } + + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitD2F(D2F o){ + stack().pop(); + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitD2I(D2I o){ + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitD2L(D2L o){ + stack().pop(); + stack().push(Type.LONG); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDADD(DADD o){ + stack().pop(); + stack().pop(); + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDALOAD(DALOAD o){ + stack().pop(); + stack().pop(); + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDASTORE(DASTORE o){ + stack().pop(); + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDCMPG(DCMPG o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDCMPL(DCMPL o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDCONST(DCONST o){ + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDDIV(DDIV o){ + stack().pop(); + stack().pop(); + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDLOAD(DLOAD o){ + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDMUL(DMUL o){ + stack().pop(); + stack().pop(); + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDNEG(DNEG o){ + stack().pop(); + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDREM(DREM o){ + stack().pop(); + stack().pop(); + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDRETURN(DRETURN o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDSTORE(DSTORE o){ + locals().set(o.getIndex(), stack().pop()); + locals().set(o.getIndex()+1, Type.UNKNOWN); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDSUB(DSUB o){ + stack().pop(); + stack().pop(); + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDUP(DUP o){ + Type t = stack().pop(); + stack().push(t); + stack().push(t); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDUP_X1(DUP_X1 o){ + Type w1 = stack().pop(); + Type w2 = stack().pop(); + stack().push(w1); + stack().push(w2); + stack().push(w1); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDUP_X2(DUP_X2 o){ + Type w1 = stack().pop(); + Type w2 = stack().pop(); + if (w2.getSize() == 2){ + stack().push(w1); + stack().push(w2); + stack().push(w1); + } + else{ + Type w3 = stack().pop(); + stack().push(w1); + stack().push(w3); + stack().push(w2); + stack().push(w1); + } + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDUP2(DUP2 o){ + Type t = stack().pop(); + if (t.getSize() == 2){ + stack().push(t); + stack().push(t); + } + else{ // t.getSize() is 1 + Type u = stack().pop(); + stack().push(u); + stack().push(t); + stack().push(u); + stack().push(t); + } + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDUP2_X1(DUP2_X1 o){ + Type t = stack().pop(); + if (t.getSize() == 2){ + Type u = stack().pop(); + stack().push(t); + stack().push(u); + stack().push(t); + } + else{ //t.getSize() is1 + Type u = stack().pop(); + Type v = stack().pop(); + stack().push(u); + stack().push(t); + stack().push(v); + stack().push(u); + stack().push(t); + } + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitDUP2_X2(DUP2_X2 o){ + Type t = stack().pop(); + if (t.getSize() == 2){ + Type u = stack().pop(); + if (u.getSize() == 2){ + stack().push(t); + stack().push(u); + stack().push(t); + }else{ + Type v = stack().pop(); + stack().push(t); + stack().push(v); + stack().push(u); + stack().push(t); + } + } + else{ //t.getSize() is 1 + Type u = stack().pop(); + Type v = stack().pop(); + if (v.getSize() == 2){ + stack().push(u); + stack().push(t); + stack().push(v); + stack().push(u); + stack().push(t); + }else{ + Type w = stack().pop(); + stack().push(u); + stack().push(t); + stack().push(w); + stack().push(v); + stack().push(u); + stack().push(t); + } + } + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitF2D(F2D o){ + stack().pop(); + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitF2I(F2I o){ + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitF2L(F2L o){ + stack().pop(); + stack().push(Type.LONG); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFADD(FADD o){ + stack().pop(); + stack().pop(); + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFALOAD(FALOAD o){ + stack().pop(); + stack().pop(); + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFASTORE(FASTORE o){ + stack().pop(); + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFCMPG(FCMPG o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFCMPL(FCMPL o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFCONST(FCONST o){ + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFDIV(FDIV o){ + stack().pop(); + stack().pop(); + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFLOAD(FLOAD o){ + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFMUL(FMUL o){ + stack().pop(); + stack().pop(); + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFNEG(FNEG o){ + stack().pop(); + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFREM(FREM o){ + stack().pop(); + stack().pop(); + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFRETURN(FRETURN o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFSTORE(FSTORE o){ + locals().set(o.getIndex(), stack().pop()); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitFSUB(FSUB o){ + stack().pop(); + stack().pop(); + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitGETFIELD(GETFIELD o){ + stack().pop(); + Type t = o.getFieldType(cpg); + if ( t.equals(Type.BOOLEAN) || + t.equals(Type.CHAR) || + t.equals(Type.BYTE) || + t.equals(Type.SHORT) ) { + t = Type.INT; + } + stack().push(t); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitGETSTATIC(GETSTATIC o){ + Type t = o.getFieldType(cpg); + if ( t.equals(Type.BOOLEAN) || + t.equals(Type.CHAR) || + t.equals(Type.BYTE) || + t.equals(Type.SHORT) ) { + t = Type.INT; + } + stack().push(t); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitGOTO(GOTO o){ + // no stack changes. + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitGOTO_W(GOTO_W o){ + // no stack changes. + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitI2B(I2B o){ + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitI2C(I2C o){ + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitI2D(I2D o){ + stack().pop(); + stack().push(Type.DOUBLE); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitI2F(I2F o){ + stack().pop(); + stack().push(Type.FLOAT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitI2L(I2L o){ + stack().pop(); + stack().push(Type.LONG); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitI2S(I2S o){ + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIADD(IADD o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIALOAD(IALOAD o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIAND(IAND o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIASTORE(IASTORE o){ + stack().pop(); + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitICONST(ICONST o){ + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIDIV(IDIV o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIF_ACMPEQ(IF_ACMPEQ o){ + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIF_ACMPNE(IF_ACMPNE o){ + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIF_ICMPEQ(IF_ICMPEQ o){ + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIF_ICMPGE(IF_ICMPGE o){ + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIF_ICMPGT(IF_ICMPGT o){ + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIF_ICMPLE(IF_ICMPLE o){ + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIF_ICMPLT(IF_ICMPLT o){ + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIF_ICMPNE(IF_ICMPNE o){ + stack().pop(); + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIFEQ(IFEQ o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIFGE(IFGE o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIFGT(IFGT o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIFLE(IFLE o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIFLT(IFLT o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIFNE(IFNE o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIFNONNULL(IFNONNULL o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIFNULL(IFNULL o){ + stack().pop(); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIINC(IINC o){ + // stack is not changed. + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitILOAD(ILOAD o){ + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitIMUL(IMUL o){ + stack().pop(); + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitINEG(INEG o){ + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitINSTANCEOF(INSTANCEOF o){ + stack().pop(); + stack().push(Type.INT); + } + /** Symbolically executes the corresponding Java Virtual Machine instruction. */ + public void visitINVOKEINTERFACE(INVOKEINTERFACE o){ + stack().pop(); //objectref + for (int i=0; i stack().slotsUsed()){ + constraintViolated((Instruction) o, "Cannot consume "+consume+" stack slots: only "+stack().slotsUsed()+" slot(s) left on stack!\nStack:\n"+stack()); + } + + int produce = o.produceStack(cpg) - ((Instruction) o).consumeStack(cpg); // Stack values are always consumed first; then produced. + if ( produce + stack().slotsUsed() > stack().maxStack() ){ + constraintViolated((Instruction) o, "Cannot produce "+produce+" stack slots: only "+(stack().maxStack()-stack().slotsUsed())+" free stack slot(s) left.\nStack:\n"+stack()); + } + } + + /***************************************************************/ + /* "generic"visitXXXX methods where XXXX is an interface */ + /* therefore, we don't know the order of visiting; but we know */ + /* these methods are called before the visitYYYY methods below */ + /***************************************************************/ + + /** + * Assures the generic preconditions of a LoadClass instance. + * The referenced class is loaded and pass2-verified. + */ + public void visitLoadClass(LoadClass o){ + ObjectType t = o.getLoadClassType(cpg); + if (t != null){// null means "no class is loaded" + Verifier v = VerifierFactory.getVerifier(t.getClassName()); + VerificationResult vr = v.doPass2(); + if (vr.getStatus() != VerificationResult.VERIFIED_OK){ + constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded and resolved: '"+vr+"'."); + } + } + } + + /** + * Ensures the general preconditions of a StackConsumer instance. + */ + public void visitStackConsumer(StackConsumer o){ + _visitStackAccessor((Instruction) o); + } + + /** + * Ensures the general preconditions of a StackProducer instance. + */ + public void visitStackProducer(StackProducer o){ + _visitStackAccessor((Instruction) o); + } + + + /***************************************************************/ + /* "generic" visitYYYY methods where YYYY is a superclass. */ + /* therefore, we know the order of visiting; we know */ + /* these methods are called after the visitXXXX methods above. */ + /***************************************************************/ + /** + * Ensures the general preconditions of a CPInstruction instance. + */ + public void visitCPInstruction(CPInstruction o){ + int idx = o.getIndex(); + if ((idx < 0) || (idx >= cpg.getSize())){ + throw new AssertionViolatedException("Huh?! Constant pool index of instruction '"+o+"' illegal? Pass 3a should have checked this!"); + } + } + + /** + * Ensures the general preconditions of a FieldInstruction instance. + */ + public void visitFieldInstruction(FieldInstruction o){ + // visitLoadClass(o) has been called before: Every FieldOrMethod + // implements LoadClass. + // visitCPInstruction(o) has been called before. + // A FieldInstruction may be: GETFIELD, GETSTATIC, PUTFIELD, PUTSTATIC + Constant c = cpg.getConstant(o.getIndex()); + if (!(c instanceof ConstantFieldref)){ + constraintViolated(o, "Index '"+o.getIndex()+"' should refer to a CONSTANT_Fieldref_info structure, but refers to '"+c+"'."); + } + // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o). + Type t = o.getType(cpg); + if (t instanceof ObjectType){ + String name = ((ObjectType)t).getClassName(); + Verifier v = VerifierFactory.getVerifier( name ); + VerificationResult vr = v.doPass2(); + if (vr.getStatus() != VerificationResult.VERIFIED_OK){ + constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'."); + } + } + } + + /** + * Ensures the general preconditions of an InvokeInstruction instance. + */ + public void visitInvokeInstruction(InvokeInstruction o){ + // visitLoadClass(o) has been called before: Every FieldOrMethod + // implements LoadClass. + // visitCPInstruction(o) has been called before. + //TODO + } + + /** + * Ensures the general preconditions of a StackInstruction instance. + */ + public void visitStackInstruction(StackInstruction o){ + _visitStackAccessor(o); + } + + /** + * Assures the generic preconditions of a LocalVariableInstruction instance. + * That is, the index of the local variable must be valid. + */ + public void visitLocalVariableInstruction(LocalVariableInstruction o){ + if (locals().maxLocals() <= (o.getType(cpg).getSize()==1? o.getIndex() : o.getIndex()+1) ){ + constraintViolated(o, "The 'index' is not a valid index into the local variable array."); + } + } + + /** + * Assures the generic preconditions of a LoadInstruction instance. + */ + public void visitLoadInstruction(LoadInstruction o){ + //visitLocalVariableInstruction(o) is called before, because it is more generic. + + // LOAD instructions must not read Type.UNKNOWN + if (locals().get(o.getIndex()) == Type.UNKNOWN){ + constraintViolated(o, "Read-Access on local variable "+o.getIndex()+" with unknown content."); + } + + // LOAD instructions, two-slot-values at index N must have Type.UNKNOWN + // as a symbol for the higher halve at index N+1 + // [suppose some instruction put an int at N+1--- our double at N is defective] + if (o.getType(cpg).getSize() == 2){ + if (locals().get(o.getIndex()+1) != Type.UNKNOWN){ + constraintViolated(o, "Reading a two-locals value from local variables "+o.getIndex()+" and "+(o.getIndex()+1)+" where the latter one is destroyed."); + } + } + + // LOAD instructions must read the correct type. + if (!(o instanceof ALOAD)){ + if (locals().get(o.getIndex()) != o.getType(cpg) ){ + constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '"+locals().get(o.getIndex())+"'; Instruction type: '"+o.getType(cpg)+"'."); + } + } + else{ // we deal with an ALOAD + if (!(locals().get(o.getIndex()) instanceof ReferenceType)){ + constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '"+locals().get(o.getIndex())+"'; Instruction expects a ReferenceType."); + } + // ALOAD __IS ALLOWED__ to put uninitialized objects onto the stack! + //referenceTypeIsInitialized(o, (ReferenceType) (locals().get(o.getIndex()))); + } + + // LOAD instructions must have enough free stack slots. + if ((stack().maxStack() - stack().slotsUsed()) < o.getType(cpg).getSize()){ + constraintViolated(o, "Not enough free stack slots to load a '"+o.getType(cpg)+"' onto the OperandStack."); + } + } + + /** + * Assures the generic preconditions of a StoreInstruction instance. + */ + public void visitStoreInstruction(StoreInstruction o){ + //visitLocalVariableInstruction(o) is called before, because it is more generic. + + if (stack().isEmpty()){ // Don't bother about 1 or 2 stack slots used. This check is implicitely done below while type checking. + constraintViolated(o, "Cannot STORE: Stack to read from is empty."); + } + + if ( (!(o instanceof ASTORE)) ){ + if (! (stack().peek() == o.getType(cpg)) ){// the other xSTORE types are singletons in BCEL. + constraintViolated(o, "Stack top type and STOREing Instruction type mismatch: Stack top: '"+stack().peek()+"'; Instruction type: '"+o.getType(cpg)+"'."); + } + } + else{ // we deal with ASTORE + Type stacktop = stack().peek(); + if ( (!(stacktop instanceof ReferenceType)) && (!(stacktop instanceof ReturnaddressType)) ){ + constraintViolated(o, "Stack top type and STOREing Instruction type mismatch: Stack top: '"+stack().peek()+"'; Instruction expects a ReferenceType or a ReturnadressType."); + } + //if (stacktop instanceof ReferenceType){ + // referenceTypeIsInitialized(o, (ReferenceType) stacktop); + //} + } + } + + /** + * Assures the generic preconditions of a ReturnInstruction instance. + */ + public void visitReturnInstruction(ReturnInstruction o){ + Type method_type = mg.getType(); + if (method_type == Type.BOOLEAN || + method_type == Type.BYTE || + method_type == Type.SHORT || + method_type == Type.CHAR){ + method_type = Type.INT; + } + + if (o instanceof RETURN){ + if (method_type != Type.VOID){ + constraintViolated(o, "RETURN instruction in non-void method."); + } + else{ + return; + } + } + if (o instanceof ARETURN){ + if (stack().peek() == Type.NULL){ + return; + } + else{ + if (! (stack().peek() instanceof ReferenceType)){ + constraintViolated(o, "Reference type expected on top of stack, but is: '"+stack().peek()+"'."); + } + referenceTypeIsInitialized(o, (ReferenceType) (stack().peek())); + //ReferenceType objectref = (ReferenceType) (stack().peek()); + // TODO: This can only be checked if using Staerk-et-al's "set of object types" instead of a + // "wider cast object type" created during verification. + //if (! (objectref.isAssignmentCompatibleWith(mg.getType())) ){ + // constraintViolated(o, "Type on stack top which should be returned is a '"+stack().peek()+"' which is not assignment compatible with the return type of this method, '"+mg.getType()+"'."); + //} + } + } + else{ + if (! ( method_type.equals( stack().peek() ))){ + constraintViolated(o, "Current method has return type of '"+mg.getType()+"' expecting a '"+method_type+"' on top of the stack. But stack top is a '"+stack().peek()+"'."); + } + } + } + + /***************************************************************/ + /* "special"visitXXXX methods for one type of instruction each */ + /***************************************************************/ + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitAALOAD(AALOAD o){ + Type arrayref = stack().peek(1); + Type index = stack().peek(0); + + indexOfInt(o, index); + if (arrayrefOfArrayType(o, arrayref)){ + if (! (((ArrayType) arrayref).getElementType() instanceof ReferenceType)){ + constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of "+((ArrayType) arrayref).getElementType()+"."); + } + //referenceTypeIsInitialized(o, (ReferenceType) (((ArrayType) arrayref).getElementType())); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitAASTORE(AASTORE o){ + try { + Type arrayref = stack().peek(2); + Type index = stack().peek(1); + Type value = stack().peek(0); + + indexOfInt(o, index); + if (!(value instanceof ReferenceType)){ + constraintViolated(o, "The 'value' is not of a ReferenceType but of type "+value+"."); + }else{ + //referenceTypeIsInitialized(o, (ReferenceType) value); + } + // Don't bother further with "referenceTypeIsInitialized()", there are no arrays + // of an uninitialized object type. + if (arrayrefOfArrayType(o, arrayref)){ + if (! (((ArrayType) arrayref).getElementType() instanceof ReferenceType)){ + constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of "+((ArrayType) arrayref).getElementType()+"."); + } + if (! ((ReferenceType)value).isAssignmentCompatibleWith((ReferenceType) ((ArrayType) arrayref).getElementType())){ + constraintViolated(o, "The type of 'value' ('"+value+"') is not assignment compatible to the components of the array 'arrayref' refers to. ('"+((ArrayType) arrayref).getElementType()+"')"); + } + } + } catch (ClassNotFoundException e) { + // FIXME: maybe not the best way to handle this + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitACONST_NULL(ACONST_NULL o){ + // Nothing needs to be done here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitALOAD(ALOAD o){ + //visitLoadInstruction(LoadInstruction) is called before. + + // Nothing else needs to be done here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitANEWARRAY(ANEWARRAY o){ + if (!stack().peek().equals(Type.INT)) { + constraintViolated(o, "The 'count' at the stack top is not of type '"+Type.INT+"' but of type '"+stack().peek()+"'."); + // The runtime constant pool item at that index must be a symbolic reference to a class, + // array, or interface type. See Pass 3a. + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitARETURN(ARETURN o){ + if (! (stack().peek() instanceof ReferenceType) ){ + constraintViolated(o, "The 'objectref' at the stack top is not of a ReferenceType but of type '"+stack().peek()+"'."); + } + ReferenceType objectref = (ReferenceType) (stack().peek()); + referenceTypeIsInitialized(o, objectref); + + // The check below should already done via visitReturnInstruction(ReturnInstruction), see there. + // It cannot be done using Staerk-et-al's "set of object types" instead of a + // "wider cast object type", anyway. + //if (! objectref.isAssignmentCompatibleWith(mg.getReturnType() )){ + // constraintViolated(o, "The 'objectref' type "+objectref+" at the stack top is not assignment compatible with the return type '"+mg.getReturnType()+"' of the method."); + //} + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitARRAYLENGTH(ARRAYLENGTH o){ + Type arrayref = stack().peek(0); + arrayrefOfArrayType(o, arrayref); + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitASTORE(ASTORE o){ + if (! ( (stack().peek() instanceof ReferenceType) || (stack().peek() instanceof ReturnaddressType) ) ){ + constraintViolated(o, "The 'objectref' is not of a ReferenceType or of ReturnaddressType but of "+stack().peek()+"."); + } + //if (stack().peek() instanceof ReferenceType){ + // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) ); + //} + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitATHROW(ATHROW o){ + try { + // It's stated that 'objectref' must be of a ReferenceType --- but since Throwable is + // not derived from an ArrayType, it follows that 'objectref' must be of an ObjectType or Type.NULL. + if (! ((stack().peek() instanceof ObjectType) || (stack().peek().equals(Type.NULL))) ){ + constraintViolated(o, "The 'objectref' is not of an (initialized) ObjectType but of type "+stack().peek()+"."); + } + + // NULL is a subclass of every class, so to speak. + if (stack().peek().equals(Type.NULL)) { + return; + } + + ObjectType exc = (ObjectType) (stack().peek()); + ObjectType throwable = (ObjectType) (Type.getType("Ljava/lang/Throwable;")); + if ( (! (exc.subclassOf(throwable)) ) && (! (exc.equals(throwable))) ){ + constraintViolated(o, "The 'objectref' is not of class Throwable or of a subclass of Throwable, but of '"+stack().peek()+"'."); + } + } catch (ClassNotFoundException e) { + // FIXME: maybe not the best way to handle this + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitBALOAD(BALOAD o){ + Type arrayref = stack().peek(1); + Type index = stack().peek(0); + indexOfInt(o, index); + if (arrayrefOfArrayType(o, arrayref)){ + if (! ( (((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN)) || + (((ArrayType) arrayref).getElementType().equals(Type.BYTE)) ) ){ + constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '"+((ArrayType) arrayref).getElementType()+"'."); + } + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitBASTORE(BASTORE o){ + Type arrayref = stack().peek(2); + Type index = stack().peek(1); + Type value = stack().peek(0); + + indexOfInt(o, index); + valueOfInt(o, value); + if (arrayrefOfArrayType(o, arrayref)){ + if (! ( (((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN)) || + (((ArrayType) arrayref).getElementType().equals(Type.BYTE)) ) ) { + constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '"+((ArrayType) arrayref).getElementType()+"'."); + } + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitBIPUSH(BIPUSH o){ + // Nothing to do... + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitBREAKPOINT(BREAKPOINT o){ + throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as BREAKPOINT."); + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitCALOAD(CALOAD o){ + Type arrayref = stack().peek(1); + Type index = stack().peek(0); + + indexOfInt(o, index); + arrayrefOfArrayType(o, arrayref); + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitCASTORE(CASTORE o){ + Type arrayref = stack().peek(2); + Type index = stack().peek(1); + Type value = stack().peek(0); + + indexOfInt(o, index); + valueOfInt(o, value); + if (arrayrefOfArrayType(o, arrayref)){ + if (! ((ArrayType) arrayref).getElementType().equals(Type.CHAR) ){ + constraintViolated(o, "The 'arrayref' does not refer to an array with elements of type char but to an array of type "+((ArrayType) arrayref).getElementType()+"."); + } + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitCHECKCAST(CHECKCAST o){ + // The objectref must be of type reference. + Type objectref = stack().peek(0); + if (!(objectref instanceof ReferenceType)){ + constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type "+objectref+"."); + } + //else{ + // referenceTypeIsInitialized(o, (ReferenceType) objectref); + //} + // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the + // current class (3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant + // pool item at the index must be a symbolic reference to a class, array, or interface type. + Constant c = cpg.getConstant(o.getIndex()); + if (! (c instanceof ConstantClass)){ + constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '"+c+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitD2F(D2F o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitD2I(D2I o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitD2L(D2L o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDADD(DADD o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.DOUBLE){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDALOAD(DALOAD o){ + indexOfInt(o, stack().peek()); + if (stack().peek(1) == Type.NULL){ + return; + } + if (! (stack().peek(1) instanceof ArrayType)){ + constraintViolated(o, "Stack next-to-top must be of type double[] but is '"+stack().peek(1)+"'."); + } + Type t = ((ArrayType) (stack().peek(1))).getBasicType(); + if (t != Type.DOUBLE){ + constraintViolated(o, "Stack next-to-top must be of type double[] but is '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDASTORE(DASTORE o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + indexOfInt(o, stack().peek(1)); + if (stack().peek(2) == Type.NULL){ + return; + } + if (! (stack().peek(2) instanceof ArrayType)){ + constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '"+stack().peek(2)+"'."); + } + Type t = ((ArrayType) (stack().peek(2))).getBasicType(); + if (t != Type.DOUBLE){ + constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '"+stack().peek(2)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDCMPG(DCMPG o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.DOUBLE){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDCMPL(DCMPL o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.DOUBLE){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDCONST(DCONST o){ + // There's nothing to be done here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDDIV(DDIV o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.DOUBLE){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDLOAD(DLOAD o){ + //visitLoadInstruction(LoadInstruction) is called before. + + // Nothing else needs to be done here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDMUL(DMUL o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.DOUBLE){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDNEG(DNEG o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDREM(DREM o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.DOUBLE){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDRETURN(DRETURN o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDSTORE(DSTORE o){ + //visitStoreInstruction(StoreInstruction) is called before. + + // Nothing else needs to be done here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDSUB(DSUB o){ + if (stack().peek() != Type.DOUBLE){ + constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.DOUBLE){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDUP(DUP o){ + if (stack().peek().getSize() != 1){ + constraintViolated(o, "Won't DUP type on stack top '"+stack().peek()+"' because it must occupy exactly one slot, not '"+stack().peek().getSize()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDUP_X1(DUP_X1 o){ + if (stack().peek().getSize() != 1){ + constraintViolated(o, "Type on stack top '"+stack().peek()+"' should occupy exactly one slot, not '"+stack().peek().getSize()+"'."); + } + if (stack().peek(1).getSize() != 1){ + constraintViolated(o, "Type on stack next-to-top '"+stack().peek(1)+"' should occupy exactly one slot, not '"+stack().peek(1).getSize()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDUP_X2(DUP_X2 o){ + if (stack().peek().getSize() != 1){ + constraintViolated(o, "Stack top type must be of size 1, but is '"+stack().peek()+"' of size '"+stack().peek().getSize()+"'."); + } + if (stack().peek(1).getSize() == 2){ + return; // Form 2, okay. + } + else{ //stack().peek(1).getSize == 1. + if (stack().peek(2).getSize() != 1){ + constraintViolated(o, "If stack top's size is 1 and stack next-to-top's size is 1, stack next-to-next-to-top's size must also be 1, but is: '"+stack().peek(2)+"' of size '"+stack().peek(2).getSize()+"'."); + } + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDUP2(DUP2 o){ + if (stack().peek().getSize() == 2){ + return; // Form 2, okay. + } + else{ //stack().peek().getSize() == 1. + if (stack().peek(1).getSize() != 1){ + constraintViolated(o, "If stack top's size is 1, then stack next-to-top's size must also be 1. But it is '"+stack().peek(1)+"' of size '"+stack().peek(1).getSize()+"'."); + } + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDUP2_X1(DUP2_X1 o){ + if (stack().peek().getSize() == 2){ + if (stack().peek(1).getSize() != 1){ + constraintViolated(o, "If stack top's size is 2, then stack next-to-top's size must be 1. But it is '"+stack().peek(1)+"' of size '"+stack().peek(1).getSize()+"'."); + } + else{ + return; // Form 2 + } + } + else{ // stack top is of size 1 + if ( stack().peek(1).getSize() != 1 ){ + constraintViolated(o, "If stack top's size is 1, then stack next-to-top's size must also be 1. But it is '"+stack().peek(1)+"' of size '"+stack().peek(1).getSize()+"'."); + } + if ( stack().peek(2).getSize() != 1 ){ + constraintViolated(o, "If stack top's size is 1, then stack next-to-next-to-top's size must also be 1. But it is '"+stack().peek(2)+"' of size '"+stack().peek(2).getSize()+"'."); + } + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitDUP2_X2(DUP2_X2 o){ + + if (stack().peek(0).getSize() == 2){ + if (stack().peek(1).getSize() == 2){ + return; // Form 4 + } + else{// stack top size is 2, next-to-top's size is 1 + if ( stack().peek(2).getSize() != 1 ){ + constraintViolated(o, "If stack top's size is 2 and stack-next-to-top's size is 1, then stack next-to-next-to-top's size must also be 1. But it is '"+stack().peek(2)+"' of size '"+stack().peek(2).getSize()+"'."); + } + else{ + return; // Form 2 + } + } + } + else{// stack top is of size 1 + if (stack().peek(1).getSize() == 1){ + if ( stack().peek(2).getSize() == 2 ){ + return; // Form 3 + } + else{ + if ( stack().peek(3).getSize() == 1){ + return; // Form 1 + } + } + } + } + constraintViolated(o, "The operand sizes on the stack do not match any of the four forms of usage of this instruction."); + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitF2D(F2D o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitF2I(F2I o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitF2L(F2L o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFADD(FADD o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.FLOAT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFALOAD(FALOAD o){ + indexOfInt(o, stack().peek()); + if (stack().peek(1) == Type.NULL){ + return; + } + if (! (stack().peek(1) instanceof ArrayType)){ + constraintViolated(o, "Stack next-to-top must be of type float[] but is '"+stack().peek(1)+"'."); + } + Type t = ((ArrayType) (stack().peek(1))).getBasicType(); + if (t != Type.FLOAT){ + constraintViolated(o, "Stack next-to-top must be of type float[] but is '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFASTORE(FASTORE o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + indexOfInt(o, stack().peek(1)); + if (stack().peek(2) == Type.NULL){ + return; + } + if (! (stack().peek(2) instanceof ArrayType)){ + constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '"+stack().peek(2)+"'."); + } + Type t = ((ArrayType) (stack().peek(2))).getBasicType(); + if (t != Type.FLOAT){ + constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '"+stack().peek(2)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFCMPG(FCMPG o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.FLOAT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFCMPL(FCMPL o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.FLOAT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFCONST(FCONST o){ + // nothing to do here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFDIV(FDIV o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.FLOAT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFLOAD(FLOAD o){ + //visitLoadInstruction(LoadInstruction) is called before. + + // Nothing else needs to be done here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFMUL(FMUL o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.FLOAT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFNEG(FNEG o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFREM(FREM o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.FLOAT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFRETURN(FRETURN o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFSTORE(FSTORE o){ + //visitStoreInstruction(StoreInstruction) is called before. + + // Nothing else needs to be done here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitFSUB(FSUB o){ + if (stack().peek() != Type.FLOAT){ + constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.FLOAT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitGETFIELD(GETFIELD o){ + try { + Type objectref = stack().peek(); + if (! ( (objectref instanceof ObjectType) || (objectref == Type.NULL) ) ){ + constraintViolated(o, "Stack top should be an object reference that's not an array reference, but is '"+objectref+"'."); + } + + String field_name = o.getFieldName(cpg); + + JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName()); + Field[] fields = jc.getFields(); + Field f = null; + for (int i=0; i=0; i--){ + Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1 + Type fromDesc = argtypes[i]; + if (fromDesc == Type.BOOLEAN || + fromDesc == Type.BYTE || + fromDesc == Type.CHAR || + fromDesc == Type.SHORT){ + fromDesc = Type.INT; + } + if (! fromStack.equals(fromDesc)){ + if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){ + ReferenceType rFromStack = (ReferenceType) fromStack; + //ReferenceType rFromDesc = (ReferenceType) fromDesc; + // TODO: This can only be checked when using Staerk-et-al's "set of object types" + // instead of a "wider cast object type" created during verification. + //if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){ + // constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible)."); + //} + referenceTypeIsInitialized(o, rFromStack); + } + else{ + constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack."); + } + } + } + + Type objref = stack().peek(nargs); + if (objref == Type.NULL){ + return; + } + if (! (objref instanceof ReferenceType) ){ + constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '"+objref+"'."); + } + referenceTypeIsInitialized(o, (ReferenceType) objref); + if (!(objref instanceof ObjectType)){ + if (!(objref instanceof ArrayType)){ + constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '"+objref+"'."); // could be a ReturnaddressType + } + else{ + objref = GENERIC_ARRAY; + } + } + + // String objref_classname = ((ObjectType) objref).getClassName(); + // String theInterface = o.getClassName(cpg); + // TODO: This can only be checked if we're using Staerk-et-al's "set of object types" + // instead of "wider cast object types" generated during verification. + //if ( ! Repository.implementationOf(objref_classname, theInterface) ){ + // constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theInterface+"' as expected."); + //} + + int counted_count = 1; // 1 for the objectref + for (int i=0; i=0; i--){ + Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1 + Type fromDesc = argtypes[i]; + if (fromDesc == Type.BOOLEAN || + fromDesc == Type.BYTE || + fromDesc == Type.CHAR || + fromDesc == Type.SHORT){ + fromDesc = Type.INT; + } + if (! fromStack.equals(fromDesc)){ + if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){ + ReferenceType rFromStack = (ReferenceType) fromStack; + ReferenceType rFromDesc = (ReferenceType) fromDesc; + // TODO: This can only be checked using Staerk-et-al's "set of object types", not + // using a "wider cast object type". + if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){ + constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible)."); + } + referenceTypeIsInitialized(o, rFromStack); + } + else{ + constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack."); + } + } + } + + Type objref = stack().peek(nargs); + if (objref == Type.NULL){ + return; + } + if (! (objref instanceof ReferenceType) ){ + constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '"+objref+"'."); + } + String objref_classname = null; + if ( !(o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME))){ + referenceTypeIsInitialized(o, (ReferenceType) objref); + if (!(objref instanceof ObjectType)){ + if (!(objref instanceof ArrayType)){ + constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '"+objref+"'."); // could be a ReturnaddressType + } + else{ + objref = GENERIC_ARRAY; + } + } + + objref_classname = ((ObjectType) objref).getClassName(); + } + else{ + if (!(objref instanceof UninitializedObjectType)){ + constraintViolated(o, "Expecting an UninitializedObjectType as 'objectref' on the stack, not a '"+objref+"'. Otherwise, you couldn't invoke a method since an array has no methods (not to speak of a return address)."); + } + objref_classname = ((UninitializedObjectType) objref).getInitialized().getClassName(); + } + + + String theClass = o.getClassName(cpg); + if ( ! Repository.instanceOf(objref_classname, theClass) ){ + constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theClass+"' as expected."); + } + + } catch (ClassNotFoundException e) { + // FIXME: maybe not the best way to handle this + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitINVOKESTATIC(INVOKESTATIC o){ + try { + // Method is not native, otherwise pass 3 would not happen. + + Type t = o.getType(cpg); + if (t instanceof ObjectType){ + String name = ((ObjectType)t).getClassName(); + Verifier v = VerifierFactory.getVerifier( name ); + VerificationResult vr = v.doPass2(); + if (vr.getStatus() != VerificationResult.VERIFIED_OK){ + constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'."); + } + } + + Type[] argtypes = o.getArgumentTypes(cpg); + int nargs = argtypes.length; + + for (int i=nargs-1; i>=0; i--){ + Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1 + Type fromDesc = argtypes[i]; + if (fromDesc == Type.BOOLEAN || + fromDesc == Type.BYTE || + fromDesc == Type.CHAR || + fromDesc == Type.SHORT){ + fromDesc = Type.INT; + } + if (! fromStack.equals(fromDesc)){ + if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){ + ReferenceType rFromStack = (ReferenceType) fromStack; + ReferenceType rFromDesc = (ReferenceType) fromDesc; + // TODO: This check can possibly only be done using Staerk-et-al's "set of object types" + // instead of a "wider cast object type" created during verification. + if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){ + constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible)."); + } + referenceTypeIsInitialized(o, rFromStack); + } + else{ + constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack."); + } + } + } + } catch (ClassNotFoundException e) { + // FIXME: maybe not the best way to handle this + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){ + try { + // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o). + + Type t = o.getType(cpg); + if (t instanceof ObjectType){ + String name = ((ObjectType)t).getClassName(); + Verifier v = VerifierFactory.getVerifier( name ); + VerificationResult vr = v.doPass2(); + if (vr.getStatus() != VerificationResult.VERIFIED_OK){ + constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'."); + } + } + + + Type[] argtypes = o.getArgumentTypes(cpg); + int nargs = argtypes.length; + + for (int i=nargs-1; i>=0; i--){ + Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1 + Type fromDesc = argtypes[i]; + if (fromDesc == Type.BOOLEAN || + fromDesc == Type.BYTE || + fromDesc == Type.CHAR || + fromDesc == Type.SHORT){ + fromDesc = Type.INT; + } + if (! fromStack.equals(fromDesc)){ + if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){ + ReferenceType rFromStack = (ReferenceType) fromStack; + ReferenceType rFromDesc = (ReferenceType) fromDesc; + // TODO: This can possibly only be checked when using Staerk-et-al's "set of object types" instead + // of a single "wider cast object type" created during verification. + if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){ + constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible)."); + } + referenceTypeIsInitialized(o, rFromStack); + } + else{ + constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack."); + } + } + } + + Type objref = stack().peek(nargs); + if (objref == Type.NULL){ + return; + } + if (! (objref instanceof ReferenceType) ){ + constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '"+objref+"'."); + } + referenceTypeIsInitialized(o, (ReferenceType) objref); + if (!(objref instanceof ObjectType)){ + if (!(objref instanceof ArrayType)){ + constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '"+objref+"'."); // could be a ReturnaddressType + } + else{ + objref = GENERIC_ARRAY; + } + } + + String objref_classname = ((ObjectType) objref).getClassName(); + + String theClass = o.getClassName(cpg); + + if ( ! Repository.instanceOf(objref_classname, theClass) ){ + constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theClass+"' as expected."); + } + } catch (ClassNotFoundException e) { + // FIXME: maybe not the best way to handle this + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitIOR(IOR o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.INT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitIREM(IREM o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.INT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitIRETURN(IRETURN o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitISHL(ISHL o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.INT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitISHR(ISHR o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.INT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitISTORE(ISTORE o){ + //visitStoreInstruction(StoreInstruction) is called before. + + // Nothing else needs to be done here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitISUB(ISUB o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.INT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitIUSHR(IUSHR o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.INT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitIXOR(IXOR o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.INT){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitJSR(JSR o){ + // nothing to do here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitJSR_W(JSR_W o){ + // nothing to do here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitL2D(L2D o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitL2F(L2F o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitL2I(L2I o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLADD(LADD o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLALOAD(LALOAD o){ + indexOfInt(o, stack().peek()); + if (stack().peek(1) == Type.NULL){ + return; + } + if (! (stack().peek(1) instanceof ArrayType)){ + constraintViolated(o, "Stack next-to-top must be of type long[] but is '"+stack().peek(1)+"'."); + } + Type t = ((ArrayType) (stack().peek(1))).getBasicType(); + if (t != Type.LONG){ + constraintViolated(o, "Stack next-to-top must be of type long[] but is '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLAND(LAND o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLASTORE(LASTORE o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + indexOfInt(o, stack().peek(1)); + if (stack().peek(2) == Type.NULL){ + return; + } + if (! (stack().peek(2) instanceof ArrayType)){ + constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '"+stack().peek(2)+"'."); + } + Type t = ((ArrayType) (stack().peek(2))).getBasicType(); + if (t != Type.LONG){ + constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '"+stack().peek(2)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLCMP(LCMP o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLCONST(LCONST o){ + // Nothing to do here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLDC(LDC o){ + // visitCPInstruction is called first. + + Constant c = cpg.getConstant(o.getIndex()); + if (! ( ( c instanceof ConstantInteger) || + ( c instanceof ConstantFloat ) || + ( c instanceof ConstantString ) ) ){ + constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '"+c+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLDC_W(LDC_W o){ + // visitCPInstruction is called first. + + Constant c = cpg.getConstant(o.getIndex()); + if (! ( ( c instanceof ConstantInteger) || + ( c instanceof ConstantFloat ) || + ( c instanceof ConstantString ) ) ){ + constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '"+c+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLDC2_W(LDC2_W o){ + // visitCPInstruction is called first. + + Constant c = cpg.getConstant(o.getIndex()); + if (! ( ( c instanceof ConstantLong) || + ( c instanceof ConstantDouble ) ) ){ + constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '"+c+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLDIV(LDIV o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLLOAD(LLOAD o){ + //visitLoadInstruction(LoadInstruction) is called before. + + // Nothing else needs to be done here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLMUL(LMUL o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLNEG(LNEG o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLOOKUPSWITCH(LOOKUPSWITCH o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + // See also pass 3a. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLOR(LOR o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLREM(LREM o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLRETURN(LRETURN o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLSHL(LSHL o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLSHR(LSHR o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLSTORE(LSTORE o){ + //visitStoreInstruction(StoreInstruction) is called before. + + // Nothing else needs to be done here. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLSUB(LSUB o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLUSHR(LUSHR o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitLXOR(LXOR o){ + if (stack().peek() != Type.LONG){ + constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'."); + } + if (stack().peek(1) != Type.LONG){ + constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitMONITORENTER(MONITORENTER o){ + if (! ((stack().peek()) instanceof ReferenceType)){ + constraintViolated(o, "The stack top should be of a ReferenceType, but is '"+stack().peek()+"'."); + } + //referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) ); + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitMONITOREXIT(MONITOREXIT o){ + if (! ((stack().peek()) instanceof ReferenceType)){ + constraintViolated(o, "The stack top should be of a ReferenceType, but is '"+stack().peek()+"'."); + } + //referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) ); + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitMULTIANEWARRAY(MULTIANEWARRAY o){ + int dimensions = o.getDimensions(); + // Dimensions argument is okay: see Pass 3a. + for (int i=0; i, see Pass 3a. + + } catch (ClassNotFoundException e) { + // FIXME: maybe not the best way to handle this + throw new AssertionViolatedException("Missing class: " + e.toString()); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitRET(RET o){ + if (! (locals().get(o.getIndex()) instanceof ReturnaddressType)){ + constraintViolated(o, "Expecting a ReturnaddressType in local variable "+o.getIndex()+"."); + } + if (locals().get(o.getIndex()) == ReturnaddressType.NO_TARGET){ + throw new AssertionViolatedException("Oops: RET expecting a target!"); + } + // Other constraints such as non-allowed overlapping subroutines are enforced + // while building the Subroutines data structure. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitRETURN(RETURN o){ + if (mg.getName().equals(Constants.CONSTRUCTOR_NAME)){// If we leave an method + if ((Frame._this != null) && (!(mg.getClassName().equals(Type.OBJECT.getClassName()))) ) { + constraintViolated(o, "Leaving a constructor that itself did not call a constructor."); + } + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitSALOAD(SALOAD o){ + indexOfInt(o, stack().peek()); + if (stack().peek(1) == Type.NULL){ + return; + } + if (! (stack().peek(1) instanceof ArrayType)){ + constraintViolated(o, "Stack next-to-top must be of type short[] but is '"+stack().peek(1)+"'."); + } + Type t = ((ArrayType) (stack().peek(1))).getBasicType(); + if (t != Type.SHORT){ + constraintViolated(o, "Stack next-to-top must be of type short[] but is '"+stack().peek(1)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitSASTORE(SASTORE o){ + if (stack().peek() != Type.INT){ + constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'."); + } + indexOfInt(o, stack().peek(1)); + if (stack().peek(2) == Type.NULL){ + return; + } + if (! (stack().peek(2) instanceof ArrayType)){ + constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '"+stack().peek(2)+"'."); + } + Type t = ((ArrayType) (stack().peek(2))).getBasicType(); + if (t != Type.SHORT){ + constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '"+stack().peek(2)+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitSIPUSH(SIPUSH o){ + // nothing to do here. Generic visitXXX() methods did the trick before. + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitSWAP(SWAP o){ + if (stack().peek().getSize() != 1){ + constraintViolated(o, "The value at the stack top is not of size '1', but of size '"+stack().peek().getSize()+"'."); + } + if (stack().peek(1).getSize() != 1){ + constraintViolated(o, "The value at the stack next-to-top is not of size '1', but of size '"+stack().peek(1).getSize()+"'."); + } + } + + /** + * Ensures the specific preconditions of the said instruction. + */ + public void visitTABLESWITCH(TABLESWITCH o){ + indexOfInt(o, stack().peek()); + // See Pass 3a. + } + +} + diff --git a/src/org/apache/bcel/verifier/structurals/InstructionContext.java b/src/org/apache/bcel/verifier/structurals/InstructionContext.java new file mode 100644 index 0000000..cc04e98 --- /dev/null +++ b/src/org/apache/bcel/verifier/structurals/InstructionContext.java @@ -0,0 +1,105 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.structurals; + + +import java.util.ArrayList; +import org.apache.bcel.generic.InstructionHandle; + +/** + * An InstructionContext offers convenient access + * to information like control flow successors and + * such. + * + * @version $Id: InstructionContext.java 382272 2006-03-02 03:31:46Z tcurdt $ + * @author Enver Haase + */ +public interface InstructionContext{ + + /** + * The getTag and setTag methods may be used for + * temporary flagging, such as graph colouring. + * Nothing in the InstructionContext object depends + * on the value of the tag. JustIce does not use it. + * + * @see #setTag(int tag) + */ + public int getTag(); + + /** + * The getTag and setTag methods may be used for + * temporary flagging, such as graph colouring. + * Nothing in the InstructionContext object depends + * on the value of the tag. JustIce does not use it. + * + * @see #getTag() + */ + public void setTag(int tag); + + /** + * This method symbolically executes the Instruction + * held in the InstructionContext. + * It "merges in" the incoming execution frame situation + * (see The Java Virtual Machine Specification, 2nd + * edition, page 146). + * By so doing, the outgoing execution frame situation + * is calculated. + * + * This method is JustIce-specific and is usually of + * no sense for users of the ControlFlowGraph class. + * They should use getInstruction().accept(Visitor), + * possibly in conjunction with the ExecutionVisitor. + * + * + * @see ControlFlowGraph + * @see ExecutionVisitor + * @see #getOutFrame(ArrayList) + * @return true - if and only if the "outgoing" frame situation + * changed from the one before execute()ing. + */ + boolean execute(Frame inFrame, ArrayList executionPredecessors, InstConstraintVisitor icv, ExecutionVisitor ev); + + Frame getInFrame(); + + /** + * This method returns the outgoing execution frame situation; + * therefore it has to be calculated by execute(Frame, ArrayList) + * first. + * + * @see #execute(Frame, ArrayList, InstConstraintVisitor, ExecutionVisitor) + */ + Frame getOutFrame(ArrayList executionPredecessors); + + /** + * Returns the InstructionHandle this InstructionContext is wrapped around. + * + * @return The InstructionHandle this InstructionContext is wrapped around. + */ + InstructionHandle getInstruction(); + + /** + * Returns the usual control flow successors. + * @see #getExceptionHandlers() + */ + InstructionContext[] getSuccessors(); + + /** + * Returns the exception handlers that protect this instruction. + * They are special control flow successors. + */ + ExceptionHandler[] getExceptionHandlers(); +} diff --git a/src/org/apache/bcel/verifier/structurals/LocalVariables.java b/src/org/apache/bcel/verifier/structurals/LocalVariables.java new file mode 100644 index 0000000..0ee13f4 --- /dev/null +++ b/src/org/apache/bcel/verifier/structurals/LocalVariables.java @@ -0,0 +1,209 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.structurals; + + +import org.apache.bcel.generic.ReferenceType; +import org.apache.bcel.generic.Type; +import org.apache.bcel.verifier.exc.AssertionViolatedException; +import org.apache.bcel.verifier.exc.StructuralCodeConstraintException; + +/** + * This class implements an array of local variables used for symbolic JVM + * simulation. + * + * @version $Id: LocalVariables.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public class LocalVariables{ + /** The Type[] containing the local variable slots. */ + private Type[] locals; + + /** + * Creates a new LocalVariables object. + */ + public LocalVariables(int maxLocals){ + locals = new Type[maxLocals]; + for (int i=0; i= maxStack){ + throw new AssertionViolatedException("OperandStack too small, should have thrown proper Exception elsewhere. Stack: "+this); + } + stack.add(type); + } + + /** + * Returns the size of this OperandStack; that means, how many Type objects there are. + */ + public int size(){ + return stack.size(); + } + + /** + * Returns the number of stack slots used. + * @see #maxStack() + */ + public int slotsUsed(){ + /* XXX change this to a better implementation using a variable + that keeps track of the actual slotsUsed()-value monitoring + all push()es and pop()s. + */ + int slots = 0; + for (int i=0; i no Instruction was executed before + // => Top-Level routine (no jsr call before) + icq.add(start, new ArrayList()); + + // LOOP! + while (!icq.isEmpty()){ + InstructionContext u; + ArrayList ec; + if (!DEBUG){ + int r = random.nextInt(icq.size()); + u = icq.getIC(r); + ec = icq.getEC(r); + icq.remove(r); + } + else{ + u = icq.getIC(0); + ec = icq.getEC(0); + icq.remove(0); + } + + ArrayList oldchain = (ArrayList) (ec.clone()); + ArrayList newchain = (ArrayList) (ec.clone()); + newchain.add(u); + + if ((u.getInstruction().getInstruction()) instanceof RET){ +//System.err.println(u); + // We can only follow _one_ successor, the one after the + // JSR that was recently executed. + RET ret = (RET) (u.getInstruction().getInstruction()); + ReturnaddressType t = (ReturnaddressType) u.getOutFrame(oldchain).getLocals().get(ret.getIndex()); + InstructionContext theSuccessor = cfg.contextOf(t.getTarget()); + + // Sanity check + InstructionContext lastJSR = null; + int skip_jsr = 0; + for (int ss=oldchain.size()-1; ss >= 0; ss--){ + if (skip_jsr < 0){ + throw new AssertionViolatedException("More RET than JSR in execution chain?!"); + } +//System.err.println("+"+oldchain.get(ss)); + if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof JsrInstruction){ + if (skip_jsr == 0){ + lastJSR = (InstructionContext) oldchain.get(ss); + break; + } + else{ + skip_jsr--; + } + } + if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof RET){ + skip_jsr++; + } + } + if (lastJSR == null){ + throw new AssertionViolatedException("RET without a JSR before in ExecutionChain?! EC: '"+oldchain+"'."); + } + JsrInstruction jsr = (JsrInstruction) (lastJSR.getInstruction().getInstruction()); + if ( theSuccessor != (cfg.contextOf(jsr.physicalSuccessor())) ){ + throw new AssertionViolatedException("RET '"+u.getInstruction()+"' info inconsistent: jump back to '"+theSuccessor+"' or '"+cfg.contextOf(jsr.physicalSuccessor())+"'?"); + } + + if (theSuccessor.execute(u.getOutFrame(oldchain), newchain, icv, ev)){ + icq.add(theSuccessor, (ArrayList) newchain.clone()); + } + } + else{// "not a ret" + + // Normal successors. Add them to the queue of successors. + InstructionContext[] succs = u.getSuccessors(); + for (int s=0; sMust not be invoked on the 'top-level subroutine'. + */ + public InstructionHandle[] getEnteringJsrInstructions(); + + /** + * Returns the one and only RET that leaves the subroutine. + * Note that JustIce has a pretty rigid notion of a subroutine. + * Must not be invoked on the 'top-level subroutine'. + * + * @see org.apache.bcel.verifier.structurals.Subroutines + */ + public InstructionHandle getLeavingRET(); + + /** + * Returns all instructions that together form this subroutine. + * Note that an instruction is part of exactly one subroutine + * (the top-level code is considered to be a special subroutine) - + * else it is not reachable at all (dead code). + */ + public InstructionHandle[] getInstructions(); + + /** + * Returns if the given InstructionHandle refers to an instruction + * that is part of this subroutine. This is a convenience method + * that saves iteration over the InstructionHandle objects returned + * by getInstructions(). + * + * @see #getInstructions() + */ + public boolean contains(InstructionHandle inst); + + /** + * Returns an int[] containing the indices of the local variable slots + * accessed by this Subroutine (read-accessed, write-accessed or both); + * local variables referenced by subroutines of this subroutine are + * not included. + * + * @see #getRecursivelyAccessedLocalsIndices() + */ + public int[] getAccessedLocalsIndices(); + + /** + * Returns an int[] containing the indices of the local variable slots + * accessed by this Subroutine (read-accessed, write-accessed or both); + * local variables referenced by subroutines of this subroutine are + * included. + * + * @see #getAccessedLocalsIndices() + */ + public int[] getRecursivelyAccessedLocalsIndices(); + + /** + * Returns the subroutines that are directly called from this subroutine. + */ + public Subroutine[] subSubs(); +} diff --git a/src/org/apache/bcel/verifier/structurals/Subroutines.java b/src/org/apache/bcel/verifier/structurals/Subroutines.java new file mode 100644 index 0000000..bed934b --- /dev/null +++ b/src/org/apache/bcel/verifier/structurals/Subroutines.java @@ -0,0 +1,651 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.structurals; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Set; +import org.apache.bcel.generic.ASTORE; +import org.apache.bcel.generic.ATHROW; +import org.apache.bcel.generic.BranchInstruction; +import org.apache.bcel.generic.CodeExceptionGen; +import org.apache.bcel.generic.GotoInstruction; +import org.apache.bcel.generic.IndexedInstruction; +import org.apache.bcel.generic.Instruction; +import org.apache.bcel.generic.InstructionHandle; +import org.apache.bcel.generic.JsrInstruction; +import org.apache.bcel.generic.LocalVariableInstruction; +import org.apache.bcel.generic.MethodGen; +import org.apache.bcel.generic.RET; +import org.apache.bcel.generic.ReturnInstruction; +import org.apache.bcel.generic.Select; +import org.apache.bcel.verifier.exc.AssertionViolatedException; +import org.apache.bcel.verifier.exc.StructuralCodeConstraintException; + + /** + * Instances of this class contain information about the subroutines + * found in a code array of a method. + * This implementation considers the top-level (the instructions + * reachable without a JSR or JSR_W starting off from the first + * instruction in a code array of a method) being a special subroutine; + * see getTopLevel() for that. + * Please note that the definition of subroutines in the Java Virtual + * Machine Specification, Second Edition is somewhat incomplete. + * Therefore, JustIce uses an own, more rigid notion. + * Basically, a subroutine is a piece of code that starts at the target + * of a JSR of JSR_W instruction and ends at a corresponding RET + * instruction. Note also that the control flow of a subroutine + * may be complex and non-linear; and that subroutines may be nested. + * JustIce also mandates subroutines not to be protected by exception + * handling code (for the sake of control flow predictability). + * To understand JustIce's notion of subroutines, please read + * + * TODO: refer to the paper. + * + * @version $Id: Subroutines.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + * @see #getTopLevel() + */ +public class Subroutines{ + /** + * This inner class implements the Subroutine interface. + */ + private class SubroutineImpl implements Subroutine{ + /** + * UNSET, a symbol for an uninitialized localVariable + * field. This is used for the "top-level" Subroutine; + * i.e. no subroutine. + */ + private static final int UNSET = -1; + + /** + * The Local Variable slot where the first + * instruction of this subroutine (an ASTORE) stores + * the JsrInstruction's ReturnAddress in and + * the RET of this subroutine operates on. + */ + private int localVariable = UNSET; + + /** The instructions that belong to this subroutine. */ + private Set instructions = new HashSet(); // Elements: InstructionHandle + + /* + * Refer to the Subroutine interface for documentation. + */ + public boolean contains(InstructionHandle inst){ + return instructions.contains(inst); + } + + /** + * The JSR or JSR_W instructions that define this + * subroutine by targeting it. + */ + private Set theJSRs = new HashSet(); + + /** + * The RET instruction that leaves this subroutine. + */ + private InstructionHandle theRET; + + /** + * Returns a String representation of this object, merely + * for debugging purposes. + * (Internal) Warning: Verbosity on a problematic subroutine may cause + * stack overflow errors due to recursive subSubs() calls. + * Don't use this, then. + */ + public String toString(){ + String ret = "Subroutine: Local variable is '"+localVariable+"', JSRs are '"+theJSRs+"', RET is '"+theRET+"', Instructions: '"+instructions.toString()+"'."; + + ret += " Accessed local variable slots: '"; + int[] alv = getAccessedLocalsIndices(); + for (int i=0; inot a + * subroutine, the top-level, is also modeled as a Subroutine + * object. + * It is a special Subroutine object where you must not invoke + * getEnteringJsrInstructions() or getLeavingRET(). + * + * @see Subroutine#getEnteringJsrInstructions() + * @see Subroutine#getLeavingRET() + */ + public Subroutine getTopLevel(){ + return TOPLEVEL; + } + /** + * A utility method that calculates the successors of a given InstructionHandle + * in the same subroutine. That means, a RET does not have any successors + * as defined here. A JsrInstruction has its physical successor as its successor + * (opposed to its target) as defined here. + */ + private static InstructionHandle[] getSuccessors(InstructionHandle instruction){ + final InstructionHandle[] empty = new InstructionHandle[0]; + final InstructionHandle[] single = new InstructionHandle[1]; + final InstructionHandle[] pair = new InstructionHandle[2]; + + Instruction inst = instruction.getInstruction(); + + if (inst instanceof RET){ + return empty; + } + + // Terminates method normally. + if (inst instanceof ReturnInstruction){ + return empty; + } + + // Terminates method abnormally, because JustIce mandates + // subroutines not to be protected by exception handlers. + if (inst instanceof ATHROW){ + return empty; + } + + // See method comment. + if (inst instanceof JsrInstruction){ + single[0] = instruction.getNext(); + return single; + } + + if (inst instanceof GotoInstruction){ + single[0] = ((GotoInstruction) inst).getTarget(); + return single; + } + + if (inst instanceof BranchInstruction){ + if (inst instanceof Select){ + // BCEL's getTargets() returns only the non-default targets, + // thanks to Eli Tilevich for reporting. + InstructionHandle[] matchTargets = ((Select) inst).getTargets(); + InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1]; + ret[0] = ((Select) inst).getTarget(); + System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length); + return ret; + } + else{ + pair[0] = instruction.getNext(); + pair[1] = ((BranchInstruction) inst).getTarget(); + return pair; + } + } + + // default case: Fall through. + single[0] = instruction.getNext(); + return single; + } + + /** + * Returns a String representation of this object; merely for debugging puposes. + */ + public String toString(){ + return "---\n"+subroutines.toString()+"\n---\n"; + } +} diff --git a/src/org/apache/bcel/verifier/structurals/UninitializedObjectType.java b/src/org/apache/bcel/verifier/structurals/UninitializedObjectType.java new file mode 100644 index 0000000..cedffc2 --- /dev/null +++ b/src/org/apache/bcel/verifier/structurals/UninitializedObjectType.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.bcel.verifier.structurals; + + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.ObjectType; +import org.apache.bcel.generic.ReferenceType; + +/** + * This class represents an uninitialized object type; see The Java + * Virtual Machine Specification, Second Edition, page 147: 4.9.4 for + * more details. + * + * @version $Id: UninitializedObjectType.java 386056 2006-03-15 11:31:56Z tcurdt $ + * @author Enver Haase + */ +public class UninitializedObjectType extends ReferenceType implements Constants{ + + /** The "initialized" version. */ + private ObjectType initialized; + + /** Creates a new instance. */ + public UninitializedObjectType(ObjectType t){ + super(T_UNKNOWN, ""); + initialized = t; + } + + /** + * Returns the ObjectType of the same class as the one of the uninitialized object + * represented by this UninitializedObjectType instance. + */ + public ObjectType getInitialized(){ + return initialized; + } + + /** @return a hash code value for the object. + */ + public int hashCode() { return initialized.hashCode(); } + + /** + * Returns true on equality of this and o. + * Equality means the ObjectType instances of "initialized" + * equal one another in this and the o instance. + * + */ + public boolean equals(Object o){ + if (! (o instanceof UninitializedObjectType)) { + return false; + } + return initialized.equals(((UninitializedObjectType)o).initialized); + } +} diff --git a/src/org/apache/bcel/verifier/structurals/package.html b/src/org/apache/bcel/verifier/structurals/package.html new file mode 100644 index 0000000..2d8ff4b --- /dev/null +++ b/src/org/apache/bcel/verifier/structurals/package.html @@ -0,0 +1,20 @@ + + + + + + + +Provides a PassVerifier class mostly used internally by JustIce, yielding a control flow graph for public use as +a nice side effect. + +

      Package Specification

      + +Contained in this package is a PassVerifier class for use with the JustIce verifier and its utility classes. +Only the pass performing what Sun calls "Structural Constraints on Java Virtual Machine Code" +has a PassVerifier class here. JustIce calls this pass "Pass 3b". + + + diff --git a/src/plugin.yml b/src/plugin.yml index a1bb5ec..4ef8950 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -6,7 +6,6 @@ authors: - spoothie - cnaude - _Shevchik_ -depend: [ProtocolLib] main: com.cnaude.chairs.Chairs commands: chairs: