You can subscribe to this list here.
2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(2) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
|
Feb
|
Mar
(16) |
Apr
(83) |
May
(27) |
Jun
(14) |
Jul
(11) |
Aug
(22) |
Sep
|
Oct
|
Nov
|
Dec
|
From: <mic...@us...> - 2007-08-27 15:14:37
|
Revision: 174 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=174&view=rev Author: michael_baer Date: 2007-08-27 08:14:38 -0700 (Mon, 27 Aug 2007) Log Message: ----------- - Added support for Big and Little Endian Applications on ARM - Added memory implementations for big endian Modified Paths: -------------- rvmroot.patch src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java src/org/binarytranslator/generic/os/loader/elf/ELF_File.java src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java Added Paths: ----------- src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java Modified: rvmroot.patch =================================================================== --- rvmroot.patch 2007-08-24 17:51:46 UTC (rev 173) +++ rvmroot.patch 2007-08-27 15:14:38 UTC (rev 174) @@ -146,7 +146,7 @@ [Lorg/jikesrvm/compilers/opt/OPT_Simplifier$DefUseEffect; [Lorg/jikesrvm/compilers/opt/ir/OPT_Operator; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ELF_Identity$AddressSize; -+[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ELF_Identity$ByteOrder; ++[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ByteOrder; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$Header$ObjectFileType; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$SegmentRange; +[Lorg/binarytranslator/vmInterface/DummyDynamicCodeRunner; @@ -157,4 +157,6 @@ +[Lorg/binarytranslator/arch/arm/decoder/ARM_Instructions$Instruction$Condition; +[Lorg/binarytranslator/arch/arm/decoder/ARM_Instructions$DataProcessing$Opcode; +[Lorg/binarytranslator/arch/arm/decoder/ARM_Instructions$OperandWrapper$ShiftType; ++[Lorg/binarytranslator/arch/arm/decoder/ARM_Laziness$Operation; ++[Lorg/binarytranslator/arch/arm/decoder/ARM_Laziness$Flag; \ No newline at end of file Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-27 15:14:38 UTC (rev 174) @@ -1,5 +1,7 @@ package org.binarytranslator.arch.arm.decoder; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; + public class ARM_Options { public enum FlagBehaviour { @@ -39,6 +41,9 @@ /** Sets the memory model that ARM shall use. */ public static MemoryModel memoryModel = MemoryModel.IntAddressed; + /** Override the byte order read from the ELF file. */ + public static ByteOrder enforcedByteOrder = null; + public static void parseOption(String key, String value) { if (key.equalsIgnoreCase("optimizeByProfiling")) { optimizeTranslationByProfiling = Boolean.parseBoolean(value); @@ -50,7 +55,9 @@ memoryModel = ARM_Options.MemoryModel.valueOf(value); } else if (key.equalsIgnoreCase("optimizedFlags")) { useOptimizedFlags = Boolean.parseBoolean(value); - } + } else if (key.equalsIgnoreCase("byteOrder")) { + enforcedByteOrder = ByteOrder.valueOf(value); + } else { throw new Error("Unknown ARM option: " + key); } Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-27 15:14:38 UTC (rev 174) @@ -10,9 +10,13 @@ import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.memory.ByteAddressedBigEndianMemory; import org.binarytranslator.generic.memory.ByteAddressedLittleEndianMemory; +import org.binarytranslator.generic.memory.IntAddressedBigEndianMemory; import org.binarytranslator.generic.memory.IntAddressedLittleEndianMemory; import org.binarytranslator.generic.os.loader.Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; import org.binarytranslator.generic.os.process.ProcessSpace; import org.binarytranslator.vmInterface.DBT_Trace; import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; @@ -20,11 +24,9 @@ public abstract class ARM_ProcessSpace extends ProcessSpace { - /** Registers used by this process */ public ARM_Registers registers; - /** * Debug information * @@ -38,16 +40,44 @@ } } - protected ARM_ProcessSpace() { + protected ARM_ProcessSpace(ByteOrder byteOrder) { registers = new ARM_Registers(); switch (ARM_Options.memoryModel) { case ByteAddressed: - memory = new ByteAddressedLittleEndianMemory(); + + switch (byteOrder) + { + case LittleEndian: + memory = new ByteAddressedLittleEndianMemory(); + break; + + case BigEndian: + memory = new ByteAddressedBigEndianMemory(); + break; + + default: + throw new RuntimeException("Unexpected byte order: " + byteOrder); + } + break; case IntAddressed: - memory = new IntAddressedLittleEndianMemory(); + + switch (byteOrder) + { + case LittleEndian: + memory = new IntAddressedLittleEndianMemory(); + break; + + case BigEndian: + memory = new IntAddressedBigEndianMemory(); + break; + + default: + throw new RuntimeException("Unexpected byte order: " + byteOrder); + } + break; default: @@ -79,12 +109,30 @@ public static ProcessSpace createProcessSpaceFromBinary(Loader loader) throws IOException { Loader.ABI abi = loader.getABI(); + + //determine the byte order for the memory implementation + ByteOrder byteOrder = ARM_Options.enforcedByteOrder; + + if (byteOrder == null) { + if (loader instanceof ELF_Loader) { + //read the byte order from the elf file + byteOrder = ((ELF_Loader)loader).getFile().getByteOrder(); + } + else { + byteOrder = ByteOrder.LittleEndian; + System.err.println("WARNING: Unable to deduce byte order from binary file. Defaulting to " + byteOrder); + } + } + else { + System.err.println("WARNING: Overriding byte order set by ELF file to " + byteOrder); + } + if (abi == Loader.ABI.ARM) { report("Creating ARM Linux ABI Process space"); - return new ARM_LinuxProcessSpace(); + return new ARM_LinuxProcessSpace(byteOrder); } else { report("Creating ARM image process space."); - return new ARM_ImageProcessSpace(); + return new ARM_ImageProcessSpace(byteOrder); } } Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-27 15:14:38 UTC (rev 174) @@ -10,6 +10,7 @@ import org.binarytranslator.generic.execution.GdbController.GdbTarget; import org.binarytranslator.generic.fault.InsufficientMemoryException; import org.binarytranslator.generic.os.loader.Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; public class ARM_ImageProcessSpace extends ARM_ProcessSpace { @@ -17,11 +18,8 @@ private final int STACK_SIZE = 4096 * 1000; private final int HEAP_SIZE = 4096 * 1000; - public ARM_ImageProcessSpace() { - super(); - - //make sure that pages of memory are automatically mapped in as they are requested. - //memory = new AutoMappingMemory(memory); + public ARM_ImageProcessSpace(ByteOrder byteOrder) { + super(byteOrder); } private int allocateFreeMemoryArea(int stackSize) throws InsufficientMemoryException Modified: src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-08-27 15:14:38 UTC (rev 174) @@ -10,6 +10,7 @@ import org.binarytranslator.generic.os.abi.linux.LinuxSystemCalls; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.loader.elf.ELF_Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; public class ARM_LinuxProcessSpace extends ARM_ProcessSpace { @@ -31,7 +32,9 @@ */ private int[] auxVector; - public ARM_LinuxProcessSpace() { + public ARM_LinuxProcessSpace(ByteOrder byteOrder) { + super(byteOrder); + sysCallGenerator = new Legacy(this); sysCalls = new ARM_LinuxSystemCalls(this, sysCallGenerator); } Added: src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java 2007-08-27 15:14:38 UTC (rev 174) @@ -0,0 +1,550 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.fault.SegmentationFault; + +/** + * ByteAddressedMemory: + * + * Memory is arrays of bytes, no endian conversion is performed. + * + * The string helo followed by the int of 0xcafebabe appear as: + * + * <pre> + * Byte Address| + * ----------------- + * .........07 | ca| + * .........06 | fe| + * .........05 | ba| + * .........04 | be| + * .........03 |'o'| + * .........02 |'l'| + * .........01 |'e'| + * .........00 |'H'| + * </pre> + */ +public class ByteAddressedBigEndianMemory extends CallBasedMemory { + + /** The size of a single page in bytes. */ + private static final int PAGE_SIZE = 4096; + + /** Bits in offset */ + private static final int OFFSET_BITS = 12; + + /** The number of pages */ + private static final int NUM_PAGES = 0x100000; + + /** The maximum amount of RAM available */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** The memory backing store */ + private byte readableMemory[][]; + private byte writableMemory[][]; + private byte executableMemory[][]; + + /** Do we have more optimal nio mmap operation? */ + private boolean HAVE_java_nio_FileChannelImpl_nio_mmap_file = false; + + /** + * Constructor - used when this is the instatiated class + */ + public ByteAddressedBigEndianMemory() { + this(null); + } + + /** + * Constructor - used when deriving a class + * + * @param classType + * the name of the over-riding class + */ + protected ByteAddressedBigEndianMemory(Class classType) { + super(classType != null ? classType : ByteAddressedBigEndianMemory.class); + readableMemory = new byte[NUM_PAGES][]; + writableMemory = new byte[NUM_PAGES][]; + executableMemory = new byte[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + private static final int getOffset(int address) { + return address & (PAGE_SIZE - 1); + } + + /** + * Return the page table entry part of the address + */ + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if (getPage(i) == null) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if (getPage(i) != null) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + + // Create memory + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + byte pages[][] = new byte[num_pages][PAGE_SIZE]; + + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + + if (DBT_Options.debugMemory) { + System.out.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + // Allocate pages + readableMemory[pte + i] = read ? pages[i] : null; + writableMemory[pte + i] = write ? pages[i] : null; + executableMemory[pte + i] = exec ? pages[i] : null; + } + + return addr; + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + + // Check file offset is page aligned + /*if ((offset % PAGE_SIZE) != 0) { + MemoryMapException.unalignedFileOffset(offset); + }*/ + + // Calculate number of pages + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugMemory) { + System.out.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + try { + // Get page table entry + int pte = getPTE(addr); + // Can we optimise the reads to use mmap? + if (!HAVE_java_nio_FileChannelImpl_nio_mmap_file) { + // Sub-optimal + file.seek(offset); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + // Allocate page + byte page[] = new byte[PAGE_SIZE]; + if (i == 0) { // first read, start from offset upto a page length + file.read(page, getOffset(addr), PAGE_SIZE - getOffset(addr)); + } else if (i == (num_pages - 1)) { // last read + file.read(page, 0, ((len - getOffset(addr)) % PAGE_SIZE)); + } else { + file.read(page); + } + + readableMemory[pte + i] = read ? page : null; + writableMemory[pte + i] = write ? page : null; + executableMemory[pte + i] = exec ? page : null; + } + } else { + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + // Allocate page + if (read && write) { + readableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_WRITE, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + writableMemory[pte + i] = readableMemory[pte + i]; + if (exec) { + executableMemory[pte + i] = readableMemory[pte + i]; + } + } else if (read) { + readableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + if (exec) { + executableMemory[pte + i] = readableMemory[pte + i]; + } + } else if (exec) { + executableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + } else { + throw new Error("Unable to map address 0x" + + Integer.toHexString(addr) + " with permissions " + + (read ? "r" : "-") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + } + } + return addr; + } catch (java.io.IOException e) { + throw new Error(e); + } + } + + /** + * Returns the page currently mapped at the given page table entry. + * + * @param pte + * The page table entry, for which a page is to be retrieved. + * @return + * The page mapped at the given page table entry or null, if no page is currently mapped + * to that entry. + */ + private byte[] getPage(int pte) { + + if (readableMemory[pte] != null) + return readableMemory[pte]; + + if (writableMemory[pte] != null) + return writableMemory[pte]; + + if (executableMemory[pte] != null) + return executableMemory[pte]; + + return null; + } + + /** + * Unmap a page of memory + * + * @param addr + * the address to unmap + * @param len + * the amount of memory to unmap + */ + public void unmap(int addr, int len) { + for (int i = 0; i < len; i += PAGE_SIZE) { + + int pte = getPTE(addr + i); + if (getPage(pte) != null) { + readableMemory[pte] = null; + writableMemory[pte] = null; + executableMemory[pte] = null; + } + else { + throw new Error("Unmapping memory that's not mapped addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + } + } + + /** + * Is the given address mapped into memory? + * @param addr to check + * @return true => memory is mapped + */ + public boolean isMapped(int addr) { + return getPage(getPTE(addr)) != null; + } + + /** + * @return the size of a page + */ + public int getPageSize() { + return PAGE_SIZE; + } + + /** + * Is the given address aligned on a page boundary? + * + * @param addr + * the address to check + * @return whether the address is aligned + */ + public boolean isPageAligned(int addr) { + return (addr % PAGE_SIZE) == 0; + } + + /** + * Make the given address page aligned to the page beneath it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToPage(int addr) { + return (addr >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Make the given address page aligned to the page above it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToNextPage(int addr) { + return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Perform a byte load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + final public int loadSigned8(int addr) { + try { + if (DBT_Options.debugMemory) + System.err.println("LoadS8 address: 0x" + Integer.toHexString(addr) + + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); + return readableMemory[getPTE(addr)][getOffset(addr)]; + } catch (NullPointerException e) { + System.err.println("Null pointer exception at address: 0x" + + Integer.toHexString(addr)); + throw e; + } + } + + /** + * Perform a byte load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + final public int loadUnsigned8(int addr) { + try { + if (DBT_Options.debugMemory) + System.err.println("LoadU8 address: 0x" + Integer.toHexString(addr) + + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); + return readableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; + } catch (NullPointerException e) { + System.err.println("Null pointer exception at address: 0x" + + Integer.toHexString(addr)); + throw e; + } + } + + /** + * Perform a 16bit load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned16(int addr) { + return (loadSigned8(addr) << 8) | loadUnsigned8(addr + 1); + } + + /** + * Perform a 16bit load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned16(int addr) { + return (loadUnsigned8(addr) << 8) | loadUnsigned8(addr + 1); + } + + /** + * Perform a 32bit load + * + * @param addr + * the address of the value to load + * @return the result + */ + public int load32(int addr) { + try { + return (loadSigned8(addr) << 24) | (loadUnsigned8(addr + 1) << 16) + | (loadUnsigned8(addr + 2) << 8) | loadUnsigned8(addr + 3); + } catch (Exception e) { + throw new SegmentationFault(addr); + } + } + + /** + * Perform a 8bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction8(int addr) { + if (DBT_Options.debugMemory) + System.err.println("LoadI8 address: 0x" + Integer.toHexString(addr) + + " val: " + executableMemory[getPTE(addr)][getOffset(addr)]); + return executableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; + } + + /** + * Perform a 32bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction32(int addr) { + return (loadInstruction8(addr) << 24) + | (loadInstruction8(addr + 1) << 16) + | (loadInstruction8(addr + 2) << 8) | loadInstruction8(addr + 3); + } + + /** + * Perform a byte store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public final void store8(int addr, int value) { + if (DBT_Options.debugMemory) + System.err.println("Store8 address: 0x" + Integer.toHexString(addr) + + " val: 0x" + Integer.toHexString(value & 0xFF)); + writableMemory[getPTE(addr)][getOffset(addr)] = (byte) value; + } + + /** + * Perform a 16bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store16(int addr, int value) { + store8(addr, value >> 8); + store8(addr + 1, value); + } + + /** + * Perform a 32bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store32(int addr, int value) { + try { + store8(addr, value >> 24); + store8(addr + 1, value >> 16); + store8(addr + 2, value >> 8); + store8(addr + 3, value); + } catch (Exception e) { + throw new SegmentationFault(addr); + } + } + + @Override + public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { + + while (len > 0) { + int pte = getPTE(address); + byte[] page = getPage(pte); + + if (page == null) + throw new SegmentationFault(address); + + readableMemory[pte] = newRead ? page : null; + writableMemory[pte] = newWrite ? page : null; + executableMemory[pte] = newExec ? page : null; + + address += PAGE_SIZE; + len -= PAGE_SIZE; + } + } + + @Override + public int loadInstruction16(int addr) { + return (loadInstruction8(addr) << 8) | loadInstruction8(addr + 1); + } +} Added: src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java 2007-08-27 15:14:38 UTC (rev 174) @@ -0,0 +1,669 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; + +import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.fault.SegmentationFault; +import org.vmmagic.pragma.Inline; + +/** + * IntAddressedMemory: + * + * Memory is arrays of ints, no endian conversion is performed. + * + * The string helloworld following by the int of 0xcafebabe appear as: + * + * <pre> + * Byte Address + * Int Address | 0 | 1 | 2 | 3 | + * ----------------------------- + * .........0c | ca| fe| ba| be| + * .........08 |'l'|'d'| \n| \0| + * .........04 |'o'|'W'|'o'|'r'| + * .........00 |'H'|'e'|'l'|'l'| + * </pre> + */ +public class IntAddressedBigEndianMemory extends CallBasedMemory { + /** + * The size of pages + */ + protected static final int PAGE_SIZE = 4096; + + /** + * Bits in offset + */ + protected static final int OFFSET_BITS = 12; + + /** + * The number of pages + */ + protected static final int NUM_PAGES = 0x100000; + + /** + * The maximum amount of RAM available + */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** + * The memory backing store + */ + private int readableMemory[][]; + + private int writableMemory[][]; + + private int executableMemory[][]; + + /** + * Constructor - used when this is the instatiated class + */ + public IntAddressedBigEndianMemory() { + this(null); + } + + /** + * Constructor - used when deriving a class + * + * @param classType + * the type of the over-riding class + */ + protected IntAddressedBigEndianMemory(Class classType) { + super(classType != null ? classType : IntAddressedBigEndianMemory.class); + readableMemory = new int[NUM_PAGES][]; + writableMemory = new int[NUM_PAGES][]; + executableMemory = new int[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + @Inline + private static final int getOffset(int address) { + return (address & (PAGE_SIZE - 1)) >>> 2; + } + + /** + * Return the page table entry part of the address + */ + @Inline + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Is the given address mapped into memory? + * @param addr to check + * @return true => memory is mapped + */ + public boolean isMapped(int addr) { + return getPage(getPTE(addr)) != null; + } + + /** + * @return the size of a page + */ + public int getPageSize() { + return PAGE_SIZE; + } + + /** + * Is the given address aligned on a page boundary? + * + * @param addr + * the address to check + * @return whether the address is aligned + */ + public boolean isPageAligned(int addr) { + return (addr % PAGE_SIZE) == 0; + } + + /** + * Make the given address page aligned to the page beneath it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToPage(int addr) { + return (addr >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Make the given address page aligned to the page above it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToNextPage(int addr) { + return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if (getPage(i) == null) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if (getPage(i) != null) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check that the address is page aligned + if ((addr % PAGE_SIZE) != 0) { + // if it is not, truncate the address down to the next page boundary and + // start mapping from there + int validPageCount = addr / PAGE_SIZE; + int oldStartAddress = addr; + addr = validPageCount * PAGE_SIZE; + + if (DBT.VerifyAssertions) + DBT._assert(oldStartAddress > addr); + + // we have to map more more memory now to reach the same end address + len += (oldStartAddress - addr); + } + + // Calculate number of pages + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + // Create memory + int pages[][] = new int[num_pages][PAGE_SIZE / 4]; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugRuntime) { + System.out.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + readableMemory[pte+i] = read ? pages[i] : null; + writableMemory[pte+i] = write ? pages[i] : null; + executableMemory[pte+i] = exec ? pages[i] : null; + } + return addr; + } + + /** + * Returns the page currently mapped at the given page table entry. + * + * @param pte + * The page table entry, for which a page is to be retrieved. + * @return + * The page mapped at the given page table entry or null, if no page is currently mapped + * to that entry. + */ + private int[] getPage(int pte) { + + if (readableMemory[pte] != null) + return readableMemory[pte]; + + if (writableMemory[pte] != null) + return writableMemory[pte]; + + if (executableMemory[pte] != null) + return executableMemory[pte]; + + return null; + } + + @Override + public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { + + while (len > 0) { + int pte = getPTE(address); + int[] page = getPage(pte); + + if (page == null) + throw new SegmentationFault(address); + + readableMemory[pte] = newRead ? page : null; + writableMemory[pte] = newWrite ? page : null; + executableMemory[pte] = newExec ? page : null; + + address += PAGE_SIZE; + len -= PAGE_SIZE; + } + } + + /** + * Read an int from RandomAccessFile ensuring that a byte swap isn't performed + * + * @param file + * file to read from + * @return native endian read int + */ + protected int readInt(RandomAccessFile file) throws java.io.IOException { + + return file.readByte() << 24 | (file.readUnsignedByte() << 16) + | (file.readUnsignedByte() << 8) | (file.readUnsignedByte()); + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public final int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + // Check file offset is page aligned + /*if ((offset % PAGE_SIZE) != 0) { + MemoryMapException.unalignedFileOffset(offset); + }*/ + + if (DBT_Options.debugRuntime) { + System.out.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + addr = map(addr, len, read, write, exec); + + try { + file.seek(offset); + for (int i = 0; i < len; i += 4) { + + int[] page = getPage(getPTE(addr + i)); + page[getOffset(addr + i)] = readInt(file); + } + + return addr; + + } + catch (java.io.IOException e) { + throw new Error(e); + } + } + + /** + * Unmap a page of memory + * + * @param addr + * the address to unmap + * @param len + * the amount of memory to unmap + */ + public final void unmap(int addr, int len) { + for (int i = 0; i < len; i += PAGE_SIZE) { + + int pte = getPTE(addr + i); + + if (getPage(pte) != null) { + readableMemory[pte] = null; + writableMemory[pte] = null; + executableMemory[pte] = null; + } + else { + throw new Error("Unmapping memory that's not mapped addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + } + } + + /** + * Perform a 32bit load where addr is word aligned + * + * @param addr + * the address of the value to load + * @return the result + */ + protected final int loadWordAligned32(int addr) { + return readableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a 32bit load where addr is word aligned and executable + * + * @param addr + * the address of the value to load + * @return the result + */ + protected final int loadWordAlignedInstruction32(int addr) { + return executableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a byte load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned8(int addr) { + return (loadWordAligned32(addr) << ((addr & 0x3) << 3)) >> 24; + // switch(addr & 3) { + // default: + // return (loadWordAligned32(addr) << 24) >> 24; + // case 1: + // return (loadWordAligned32(addr) << 16) >> 24; + // case 2: + // return (loadWordAligned32(addr) << 8) >> 24; + // case 3: + // return loadWordAligned32(addr) >> 24; + // } + } + + /** + * Perform a byte load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned8(int addr) { + return (loadWordAligned32(addr) >> ((3 - (addr & 3)) << 3)) & 0xFF; + // switch(addr & 3) { + // default: + // return loadWordAligned32(addr) & 0xFF; + // case 1: + // return (loadWordAligned32(addr) >> 8) & 0xFF; + // case 2: + // return (loadWordAligned32(addr) >> 16) & 0xFF; + // case 3: + // return loadWordAligned32(addr) >>> 24; + // } + } + + /** + * Perform a 16bit load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned16(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr) >> 16; + case 1: + return (loadWordAligned32(addr) << 8) >> 16; + case 2: + return (loadWordAligned32(addr) << 16) >> 16; + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr) << 24) >> 16) + | (loadWordAligned32(addr + 1) >>> 24); + } + } + + /** + * Perform a 16bit load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned16(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr) >>> 16; + case 1: + return (loadWordAligned32(addr) >> 8) & 0xFFFF; + case 2: + return loadWordAligned32(addr) & 0xFFFF; + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr) << 8) & 0xFF00) + | loadWordAligned32(addr + 1) >>> 24; + } + } + + /** + * Perform a 32bit load + * + * @param addr + * the address of the value to load + * @return the result + */ + public int load32(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr); + case 1: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr + 3) >>> 24) + | (loadWordAligned32(addr) << 8); + case 2: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr + 2) >>> 16) + | (loadWordAligned32(addr) << 16); + case 3: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr + 1) >>> 8) + | (loadWordAligned32(addr) << 24); + } + } + + /** + * Perform a 8bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction8(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr) >>> 24; + case 1: + return (loadWordAlignedInstruction32(addr) >> 16) & 0xFF; + case 2: + return (loadWordAlignedInstruction32(addr) >> 8) & 0xFF; + case 3: + return loadWordAlignedInstruction32(addr) & 0xFF; + } + } + + @Override + public int loadInstruction16(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr) >>> 16; + case 1: + return (loadWordAlignedInstruction32(addr) >> 8) & 0xFFFF; + case 2: + return loadWordAlignedInstruction32(addr) & 0xFFFF; + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAlignedInstruction32(addr) << 8) & 0xFF00) + | (loadWordAlignedInstruction32(addr + 1) >>> 25); + } + } + + /** + * Perform a 32bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction32(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr); + case 1: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr + 3) >>> 24) + | (loadWordAlignedInstruction32(addr) << 8); + case 2: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr + 2) >>> 16) + | (loadWordAlignedInstruction32(addr) << 16); + case 3: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr + 1) >>> 8) + | (loadWordAlignedInstruction32(addr) << 24); + } + } + + /** + * Perform a 32bit aligned store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + final protected void storeWordAligned32(int addr, int value) { + writableMemory[getPTE(addr)][getOffset(addr)] = value; + } + + /** + * Perform a 32bit load, from writable memory, where addr is word aligned + * + * @param addr + * the address of the value to load + * @return the result + */ + final protected int loadWordAligned32forWrite(int addr) { + return writableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a byte store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store8(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x00FFFFFF) + | (value << 24)); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF00FFFF) + | ((value & 0xFF) << 16)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF00FF) + | ((value & 0xFF) << 8)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | (value & 0xFF)); + break; + } + } + + /** + * Perform a 16bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store16(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x0000FFFF) + | (value << 16)); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF0000FF) + | ((value & 0xFFFF) << 8)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF0000) + | (value & 0xFFFF)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | ((value >> 8) & 0xFF)); + storeWordAligned32(addr + 1, + (loadWordAligned32forWrite(addr + 1) & 0x00FFFFFF) + | (value << 24)); + break; + } + } + + /** + * Perform a 32bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store32(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, value); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF000000) + | (value >>> 8)); + storeWordAligned32(addr + 3, + (loadWordAligned32forWrite(addr + 3) & 0x00FFFFFF) | (value << 24)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF0000) + | (value >>> 16)); + storeWordAligned32(addr + 2, + (loadWordAligned32forWrite(addr + 2) & 0x0000FFFF) | (value << 16)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | (value >>> 24)); + storeWordAligned32(addr + 1, + (loadWordAligned32forWrite(addr + 1) & 0x000000FF) | (value << 8)); + break; + } + } +} Modified: src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-27 15:14:38 UTC (rev 174) @@ -13,7 +13,6 @@ import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.fault.SegmentationFault; -import org.jikesrvm.VM_Configuration; import org.vmmagic.pragma.Inline; /** @@ -283,12 +282,8 @@ * @return native endian read int */ protected int readInt(RandomAccessFile file) throws java.io.IOException { - if (VM_Configuration.BuildForPowerPC) { - return file.readInt(); // NB this will always read in big-endian format - } else { - return file.readUnsignedByte() | (file.readUnsignedByte() << 8) - | (file.readUnsignedByte() << 16) | (file.readByte() << 24); - } + return file.readUnsignedByte() | (file.readUnsignedByte() << 8) + | (file.readUnsignedByte() << 16) | (file.readByte() << 24); } /** Modified: src/org/binarytranslator/generic/os/loader/elf/ELF_File.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-08-27 15:14:38 UTC (rev 174) @@ -22,7 +22,23 @@ import org.binarytranslator.generic.os.process.ProcessSpace; public class ELF_File { + + /** Represents accepted ELF byte orders. */ + public enum ByteOrder implements IdentifiedEnum { + LittleEndian(1), + BigEndian(2); + + private int identifier; + + private ByteOrder(int identifier) { + this.identifier = identifier; + } + public int getIdentifier() { + return identifier; + } + } + /** Wrapper class used for reading the ELF file with the required endianness */ private BinaryReader reader; @@ -31,6 +47,10 @@ /** Program segment headers */ private SegmentHeader segmentHeaders[]; + + public ByteOrder getByteOrder() { + return header.byteOrder; + } /** * Debug information @@ -60,9 +80,9 @@ * @return * An ELF_BinaryReader, that hides the details of the byte order. */ - public static BinaryReader create(ELF_Identity.ByteOrder byteOrder, RandomAccessFile file) { + public static BinaryReader create(ByteOrder byteOrder, RandomAccessFile file) { - if (byteOrder == ELF_Identity.ByteOrder.BigEndian) + if (byteOrder == ByteOrder.BigEndian) return new NonSwappingReader(file); else return new ByteSwappingReader(file); @@ -296,22 +316,6 @@ } } - /** Represents accepted ELF byte orders. */ - private enum ByteOrder implements IdentifiedEnum { - LittleEndian(1), - BigEndian(2); - - private int identifier; - - private ByteOrder(int identifier) { - this.identifier = identifier; - } - - public int getIdentifier() { - return identifier; - } - } - /* Symbolic names for the most widely used ABIs. This is not an enum, because the list isn't complete. */ private static final byte ELFOSABI_SYSTEMV = 0; private static final byte ELFOSABI_HPUX = 1; @@ -334,13 +338,13 @@ private static final byte ELF_MAGIC_VALUE[] = { 0x7f, 'E', 'L','F' }; /** Specifies the size of an address within this elf.*/ - private AddressSize addressSize; + AddressSize addressSize; /** The byte order used by this elf.*/ - private ByteOrder byteOrder; + ByteOrder byteOrder; /** The ABI that is used by this ELF.*/ - private byte abi; + byte abi; /** * Construct/read ELF identity Modified: src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java 2007-08-27 15:14:38 UTC (rev 174) @@ -1,7 +1,6 @@ package org.binarytranslator.generic.os.loader.elf; import java.io.IOException; - import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-24 17:51:44
|
Revision: 173 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=173&view=rev Author: michael_baer Date: 2007-08-24 10:51:46 -0700 (Fri, 24 Aug 2007) Log Message: ----------- - Missing from last commit Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/generic/decoder/CodeTranslator.java src/org/binarytranslator/generic/memory/CallBasedMemory.java src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-24 17:08:31 UTC (rev 172) +++ src/org/binarytranslator/DBT_Options.java 2007-08-24 17:51:46 UTC (rev 173) @@ -310,7 +310,7 @@ input = input.substring(pos + 1); } - if (input.length() > 1) { + if (input.length() >= 1) { state.onText(input); } } Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-08-24 17:08:31 UTC (rev 172) +++ src/org/binarytranslator/Main.java 2007-08-24 17:51:46 UTC (rev 173) @@ -86,6 +86,10 @@ return; } + if (DBT_Options.buildForSunVM) { + System.err.println("WARNING: This build was done for the SUN JVM and does only support interpretation, but not binary translation. Set DBT_Options.buildForSunVM to false to build for the Jikes RVM."); + } + if (DBT.VerifyAssertions) { System.err.println("WARNING: Assertions are enabled."); } Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-24 17:08:31 UTC (rev 172) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-24 17:51:46 UTC (rev 173) @@ -765,7 +765,7 @@ * supposedly a CALL or RETURN */ - boolean decision = DBT_Options.singleInstrTranslation == false && jump.type == BranchType.DIRECT_BRANCH && !shallTraceStop(); + boolean decision = DBT_Options.singleInstrTranslation == false && !shallTraceStop(); if (!decision) { @@ -778,10 +778,14 @@ return false; } - //only query the code cache if we have to - DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); - decision = (compiledTrace == null || compiledTrace.getNumberOfInstructions() < 20) ; + decision = jump.type == BranchType.DIRECT_BRANCH; + if (!decision) { + //only query the code cache if we have to + DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); + decision = (compiledTrace != null && compiledTrace.getNumberOfInstructions() < 30); + } + if (DBT_Options.debugBranchResolution) { String text = (!decision ? "Not inlining " : "Inlining "); text += jump.type + " to 0x" + Integer.toHexString(targetPc); Modified: src/org/binarytranslator/generic/memory/CallBasedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/CallBasedMemory.java 2007-08-24 17:08:31 UTC (rev 172) +++ src/org/binarytranslator/generic/memory/CallBasedMemory.java 2007-08-24 17:51:46 UTC (rev 173) @@ -104,12 +104,12 @@ /** * The generation context we're translating within */ - private OPT_GenerationContext gc; + protected OPT_GenerationContext gc; /** * Register that references the memory object */ - OPT_Register memory; + protected OPT_Register memory; /** * Constructor @@ -158,7 +158,7 @@ } /** - * Generate memory prologue,... for the beignning of a trace. e.g. Loading the + * Generate memory prologue,... for the beginning of a trace. e.g. Loading the * page table into a register */ public void initTranslate(CodeTranslator helper) { @@ -202,8 +202,7 @@ if (DBT_Options.inlineCallbasedMemory) { translator.appendInlinedCall(s); } - else - { + else { s.position = gc.inlineSequence; s.bcIndex = bcIndex; translator.appendInstruction(s); @@ -395,45 +394,6 @@ } /** - * Generate the IR code for a byte store - * - * @param src - * the register that holds the value to store - * @param addr - * the address of the value to store - */ - public void translateCallBasedStore8(OPT_Operand addr, - OPT_RegisterOperand src) { - translateStore(store8, DBT_Trace.MEMORY_STORE8, addr, src); - } - - /** - * Generate the IR code for a 16bit store - * - * @param src - * the register that holds the value to store - * @param addr - * the address of the value to store - */ - public void translateCallBasedStore16(OPT_Operand addr, - OPT_RegisterOperand src) { - translateStore(store16, DBT_Trace.MEMORY_STORE16, addr, src); - } - - /** - * Generate the IR code for a 32bit store - * - * @param src - * the register that holds the value to store - * @param addr - * the address of the value to store - */ - public void translateCallBasedStore32(OPT_Operand addr, - OPT_RegisterOperand src) { - translateStore(store32, DBT_Trace.MEMORY_STORE32, addr, src); - } - - /** * Get method reference if linking a call * * @param callAddress Modified: src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-24 17:08:31 UTC (rev 172) +++ src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-24 17:51:46 UTC (rev 173) @@ -87,7 +87,7 @@ * Return the offset part of the address */ @Inline - protected int getOffset(int address) { + private static final int getOffset(int address) { return (address & (PAGE_SIZE - 1)) >>> 2; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-24 17:08:32
|
Revision: 172 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=172&view=rev Author: michael_baer Date: 2007-08-24 10:08:31 -0700 (Fri, 24 Aug 2007) Log Message: ----------- - Fixed a bug where a parameter that is only one char would not be parsed correctly - Fixed a bug that I recently introduced on loads with negative offset and writeback - various smaller fixes Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-21 16:12:27 UTC (rev 171) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-24 17:08:31 UTC (rev 172) @@ -556,28 +556,13 @@ return super.inlineBranchInstruction(targetPc, jump); case DynamicJumps: - if (jump.type == BranchType.INDIRECT_BRANCH) - return true; - else - return super.inlineBranchInstruction(targetPc, jump); + return jump.type == BranchType.INDIRECT_BRANCH; - case FunctionCalls: - if (jump.type == BranchType.CALL) - return true; - else - return super.inlineBranchInstruction(targetPc, jump); + case DirectBranches: + return jump.type == BranchType.DIRECT_BRANCH; - case FunctionReturns: - if (jump.type == BranchType.CALL) - return true; - else - return super.inlineBranchInstruction(targetPc, jump); - case Functions: - if (jump.type == BranchType.CALL || jump.type == BranchType.RETURN) - return true; - else - return super.inlineBranchInstruction(targetPc, jump); + return jump.type == BranchType.CALL || jump.type == BranchType.RETURN; case All: return true; Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-08-21 16:12:27 UTC (rev 171) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-08-24 17:08:31 UTC (rev 172) @@ -248,7 +248,8 @@ if (instr.writeBack()) address += '!'; - } else { + } + else { address += "], "; if (!instr.positiveOffset()) Modified: src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java 2007-08-21 16:12:27 UTC (rev 171) +++ src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java 2007-08-24 17:08:31 UTC (rev 172) @@ -368,10 +368,12 @@ <T> T decode(short instr, ARM_InstructionFactory<T> factory) { //bit9==bit10==bit11==1? if ((instr & 0x0E00) == 0x0E00) { - if (Utils.getBit(instr, 8)) + if (Utils.getBit(instr, 8)) { return factory.createSoftwareInterrupt(instr); - else + } + else { return factory.createUndefinedInstruction(instr); + } } return factory.createBranch(instr); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-21 16:12:27 UTC (rev 171) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-24 17:08:31 UTC (rev 172) @@ -11,8 +11,7 @@ NoInlining, Default, Functions, - FunctionCalls, - FunctionReturns, + DirectBranches, DynamicJumps, All, } @@ -40,7 +39,6 @@ /** Sets the memory model that ARM shall use. */ public static MemoryModel memoryModel = MemoryModel.IntAddressed; - public static void parseOption(String key, String value) { if (key.equalsIgnoreCase("optimizeByProfiling")) { optimizeTranslationByProfiling = Boolean.parseBoolean(value); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-21 16:12:27 UTC (rev 171) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-24 17:08:31 UTC (rev 172) @@ -8,7 +8,6 @@ import org.binarytranslator.arch.arm.decoder.ARM_Instructions.Instruction.Condition; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; -import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; import org.binarytranslator.generic.branchprofile.BranchProfile.BranchType; import org.jikesrvm.classloader.VM_Atom; import org.jikesrvm.classloader.VM_MemberReference; @@ -2205,7 +2204,7 @@ return positiveOffset; } else { - OPT_RegisterOperand tmp = arm2ir.getTempInt(0); + OPT_RegisterOperand tmp = arm2ir.getTempInt(1); arm2ir.appendInstruction(Unary.create(INT_NEG, tmp, positiveOffset)); return tmp.copy(); } @@ -2241,26 +2240,14 @@ } public void translate() { - //should we simulate a user-mode memory access? If yes, store the current mode and fake a switch - //to user mode. - - //stores the current operating mode - OPT_RegisterOperand currentOperatingMode = null; - + //should we simulate a user-mode memory access? If yes, handle this using the interpreter if (i.forceUserMode) { - OPT_Instruction call_getOperatingMode = createCallToRegisters("getOperatingMode", "()A", 0); - currentOperatingMode = arm2ir.getTempOperatingMode(); - - Call.setResult(call_getOperatingMode, currentOperatingMode); - arm2ir.appendCustomCall(call_getOperatingMode); - - OPT_Instruction call_setOperatingModeWithoutRegisterLayout = createCallToRegisters("setOperatingModeWithoutRegisterLayout", "(A)", 1); - Call.setParam(call_setOperatingModeWithoutRegisterLayout, 1, arm2ir.getTempOperatingMode(OperatingMode.USR)); - - arm2ir.appendCustomCall(call_setOperatingModeWithoutRegisterLayout); + arm2ir.appendInterpretedInstruction(pc, lazy); + arm2ir.appendTraceExit(lazy, arm2ir.getRegister(ARM_Registers.PC)); + return; } - //get the address of the memory, that we're supposed access + //get the address of the memory, that we're supposed to access OPT_Operand address = resolveAddress(); if (i.isLoad) { @@ -2275,10 +2262,6 @@ //according to the ARM reference, the last two bits cause the value to be right-rotated OPT_RegisterOperand rotation = arm2ir.getTempInt(1); - - //make sure that we're not loosing the address due to the shifting - OPT_RegisterOperand adrCopy = arm2ir.getTempInt(0); - arm2ir.appendInstruction(Move.create(INT_MOVE, adrCopy, address.copy())); //rotation = (address & 0x3) * 8 arm2ir.appendInstruction(Binary.create(INT_AND, rotation, address.copy(), new OPT_IntConstantOperand(0x3))); @@ -2299,9 +2282,6 @@ //continue with the remainder of the instruction arm2ir.setCurrentBlock(remainderBlock); - - //allow further usage of the memory address - address = adrCopy; break; case HalfWord: @@ -2345,13 +2325,6 @@ throw new RuntimeException("Unexpected memory size: " + i.size); } } - - //if we were writing in user mode, then switch back to our previous operating mode - if (i.forceUserMode) { - OPT_Instruction call_setOperatingModeWithoutRegisterLayout = createCallToRegisters("setOperatingModeWithoutRegisterLayout", "(A)", 1); - Call.setParam(call_setOperatingModeWithoutRegisterLayout, 1, currentOperatingMode); - arm2ir.appendCustomCall(call_setOperatingModeWithoutRegisterLayout); - } //should the memory address, which we accessed, be written back into a register? //This is used for continuous memory accesses Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-21 16:12:27 UTC (rev 171) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-24 17:08:31 UTC (rev 172) @@ -58,7 +58,6 @@ if (registers.getThumbMode()) { int instrAddr = getCurrentInstructionAddress() & 0xFFFFFFFE; - System.out.println("Thumb syscall at: " + instrAddr); short instruction = (short)memory.loadInstruction16(instrAddr); instr = ARM_InstructionDecoder.Thumb.decode(instruction); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-21 16:12:25
|
Revision: 171 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=171&view=rev Author: michael_baer Date: 2007-08-21 09:12:27 -0700 (Tue, 21 Aug 2007) Log Message: ----------- - Fix bug in loadInstruction16 that was also present in loadUnsigned16 Modified Paths: -------------- src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java Modified: src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-21 15:29:38 UTC (rev 170) +++ src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-21 16:12:27 UTC (rev 171) @@ -519,11 +519,11 @@ public int loadInstruction16(int addr) { switch (addr & 3) { default: - return loadWordAlignedInstruction32(addr) >>> 16; + return loadWordAlignedInstruction32(addr) & 0xFFFF; case 1: return (loadWordAlignedInstruction32(addr) >> 8) & 0xFFFF; case 2: - return loadWordAlignedInstruction32(addr) & 0xFFFF; + return (loadWordAlignedInstruction32(addr) >> 16) & 0xFFFF; case 3: // 2 loads to deal with spanning int problem return (loadWordAlignedInstruction32(addr) >>> 24) | ((loadWordAlignedInstruction32(addr + 1) << 8) & 0xFF00); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-21 15:35:45
|
Revision: 170 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=170&view=rev Author: michael_baer Date: 2007-08-21 08:29:38 -0700 (Tue, 21 Aug 2007) Log Message: ----------- - Increase ARM heap & stack size to 4MB when loading embedded system images - Move some OPT_Operand.copy() calls around Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/generic/decoder/CodeTranslator.java src/org/binarytranslator/generic/execution/InterpreterController.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/DBT_Options.java 2007-08-21 15:29:38 UTC (rev 170) @@ -25,7 +25,7 @@ public final static boolean buildForSunVM = false; /** Enable the profiling of application during interpretation? */ - public final static boolean profileDuringInterpretation = true; + public final static boolean profileDuringInterpretation = false; /** Are unimplemented system calls fatal? */ public final static boolean unimplementedSystemCallsFatal = false; Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-21 15:29:38 UTC (rev 170) @@ -413,7 +413,7 @@ appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); } else { - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), op1.copy(), op2.copy(), OPT_ConditionOperand.LOWER().flipCode(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.LOWER().flipCode(), new OPT_BranchProfileOperand())); } break; @@ -431,7 +431,7 @@ case Add: case LogicalOpAfterAdd: if (ARM_Options.useOptimizedFlags) { - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); } else { OPT_RegisterOperand tmp1 = getTempInt(5); @@ -442,7 +442,7 @@ appendInstruction(Binary.create(INT_SUB, tmp2.copyRO(), new OPT_IntConstantOperand(Integer.MIN_VALUE), op2.copy())); appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, tmp_bool.copyRO(), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.GREATER_EQUAL(), new OPT_BranchProfileOperand(), op1.copy(), tmp1.copy(), OPT_ConditionOperand.GREATER(), OPT_BranchProfileOperand.unlikely())); appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, getFlag(Flag.Overflow), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS() , new OPT_BranchProfileOperand(), op1.copy(), tmp2.copy(), OPT_ConditionOperand.LESS(), OPT_BranchProfileOperand.unlikely())); - appendInstruction(Binary.create(INT_OR, getFlag(Flag.Overflow), getFlag(Flag.Overflow), tmp_bool.copy())); + appendInstruction(Binary.create(INT_OR, flagRegister, getFlag(Flag.Overflow), tmp_bool.copy())); } break; Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-21 15:29:38 UTC (rev 170) @@ -186,10 +186,10 @@ ARM_Translator translator, OperandWrapper operand) { ResolvedOperand result = new ResolvedOperand_WithShifterCarryOut(translator, operand); - return result.getValue(); + return result.getValue().copy(); } - public final OPT_Operand getValue() { + private final OPT_Operand getValue() { return value; } @@ -235,7 +235,7 @@ else { OPT_RegisterOperand tmp = translator.arm2ir.getTempInt(9); translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, translator.arm2ir.getRegister(operand.getRegister()), new OPT_IntConstantOperand(operand.getOffset()))); - value = tmp.copy(); + value = tmp; } return; @@ -382,7 +382,7 @@ curBlock.insertOut(block1); OPT_Operand carryFlag = translator.arm2ir.readCarryFlag(translator.lazy); translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), carryFlag, new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, carryFlag, new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); @@ -519,15 +519,15 @@ //block 2 - shift < 32 && shift != 0 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_SHR, resultRegister, shiftedOperand, shiftAmount.copy()) ); + translator.arm2ir.appendInstruction(Binary.create(INT_SHR, resultRegister, shiftedOperand.copy(), shiftAmount.copy()) ); translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount.copy(), new OPT_IntConstantOperand(-1)) ); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp.copy()); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), tmp.copy()); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 3 - shift >= 32 translator.arm2ir.setCurrentBlock(block3); block3.insertOut(nextBlock); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, 31); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), 31); translator.arm2ir.appendInstruction(Binary.create(INT_MUL, resultRegister.copyRO(), getShifterCarryOutTarget(), new OPT_IntConstantOperand(-1)) ); //creates either 0xFFFFFFFF if the bit is set, or 0 otherwise translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); @@ -563,7 +563,7 @@ //block 2 - Shift != 0 && Shift < 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_SUB, tmp, new OPT_IntConstantOperand(32), shiftAmount) ); + translator.arm2ir.appendInstruction(Binary.create(INT_SUB, tmp, new OPT_IntConstantOperand(32), shiftAmount.copy() ) ); translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), tmp.copy()); translator.arm2ir.appendInstruction(Binary.create(INT_SHL, resultRegister, shiftedOperand.copy(), shiftAmount.copy())); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); @@ -1600,7 +1600,7 @@ @Override public void translate() { - //Call Integer.numberOfLeadingZeros() to obtain the result of this operation + //Call Integer.numberOfLeadingZeros() to obtain the result of this operation OPT_RegisterOperand result = getResultRegister(); VM_TypeReference IntegerType = VM_TypeReference @@ -1647,7 +1647,7 @@ //swap exchanges the value of a memory address with the value in a register if (!i.swapByte) { ps.memory.translateLoad32(memAddr, tmp); - ps.memory.translateStore32(memAddr, arm2ir.getRegister(i.Rm)); + ps.memory.translateStore32(memAddr.copy(), arm2ir.getRegister(i.Rm)); //according to the ARM architecture reference, the value loaded from a memory address is rotated //by the number of ones in the first two bits of the address @@ -1659,8 +1659,8 @@ arm2ir.appendRotateRight(result, tmp.copy(), rotation.copy()); } else { - ps.memory.translateLoadUnsigned8(memAddr.copy(), tmp); - ps.memory.translateStore8(memAddr, arm2ir.getRegister(i.Rm)); + ps.memory.translateLoadUnsigned8(memAddr, tmp); + ps.memory.translateStore8(memAddr.copy(), arm2ir.getRegister(i.Rm)); arm2ir.appendInstruction(Move.create(INT_MOVE, result, tmp.copy())); } } @@ -1959,7 +1959,7 @@ //set the correct processor mode (thumb or not) OPT_Instruction s = createCallToRegisters("setThumbMode", "(Z)V", 1); - Call.setParam(s, 1, enableThumb); + Call.setParam(s, 1, enableThumb.copy()); arm2ir.appendCustomCall(s); //jump to the target address. Because we might have switched to thumb mode, we are @@ -1999,7 +1999,7 @@ arm2ir.appendInstruction(Binary.create(INT_MUL, tmp, operand1, operand2)); OPT_Operand operand3 = arm2ir.getRegister(i.Rn); - arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), tmp.copy(), operand3)); + arm2ir.appendInstruction(Binary.create(INT_ADD, result, tmp.copy(), operand3)); } else { arm2ir.appendInstruction(Binary.create(INT_MUL, result, operand1, operand2)); @@ -2050,7 +2050,7 @@ } //multiply the two operands - arm2ir.appendInstruction(Binary.create(LONG_MUL, result.copyRO(), operand1.copy(), operand2.copy())); + arm2ir.appendInstruction(Binary.create(LONG_MUL, result, operand1.copy(), operand2.copy())); if (i.accumulate) { //treat the accum. value as an unsigned value @@ -2247,7 +2247,7 @@ //stores the current operating mode OPT_RegisterOperand currentOperatingMode = null; - if (i.forceUserMode) { + if (i.forceUserMode) { OPT_Instruction call_getOperatingMode = createCallToRegisters("getOperatingMode", "()A", 0); currentOperatingMode = arm2ir.getTempOperatingMode(); @@ -2364,7 +2364,7 @@ else { //add the offset to the base address and write the result back into Rn OPT_Operand resolvedOffset = resolveOffset(); - arm2ir.appendInstruction(Binary.create(INT_ADD, writeBackTarget, address, resolvedOffset)); + arm2ir.appendInstruction(Binary.create(INT_ADD, writeBackTarget, address.copy(), resolvedOffset)); } } Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-21 15:29:38 UTC (rev 170) @@ -14,8 +14,8 @@ public class ARM_ImageProcessSpace extends ARM_ProcessSpace { private AngelSystemCalls sysCalls; - private final int STACK_SIZE = 4096 * 100; - private final int HEAP_SIZE = 4096 * 100; + private final int STACK_SIZE = 4096 * 1000; + private final int HEAP_SIZE = 4096 * 1000; public ARM_ImageProcessSpace() { super(); Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-21 15:29:38 UTC (rev 170) @@ -695,7 +695,7 @@ unresolvedDynamicBranches.add(unresolvedInfo); setCurrentBlock(fallThrough); - appendRecordUncaughtBranch(currentPC, targetAddress.copyRO(), branchType, retAddr); + appendRecordUncaughtBranch(currentPC, targetAddress, branchType, retAddr); appendTraceExit((Laziness) lazyStateAtJump.clone(), targetAddress); } Modified: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-08-21 15:29:38 UTC (rev 170) @@ -20,7 +20,8 @@ while (!ps.finished) { - Interpreter.Instruction instruction = interpreter.decode(pc); + Interpreter.Instruction instruction = interpreter.decode(pc); + //System.out.println(String.format("[%x] %s", pc, instruction.toString())); instruction.execute(); int nextInstruction = instruction.getSuccessor(pc); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-20 21:08:44
|
Revision: 169 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=169&view=rev Author: michael_baer Date: 2007-08-20 14:08:34 -0700 (Mon, 20 Aug 2007) Log Message: ----------- - Introduce option to use optimized flag handling instructions - otherwise resorting to traditional flag evaluation Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-20 14:12:59 UTC (rev 168) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-20 21:08:34 UTC (rev 169) @@ -198,6 +198,7 @@ /** Called when the ARM flags shall be set by a SUB operation. This sets all ARM flags. */ public abstract void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2); + public abstract void appendReverseSubFlags(ARM_Laziness lazy, OPT_RegisterOperand result, OPT_Operand lhs, OPT_Operand rhs); } /** Implements a flag behavior that will immediately evaluate all flag values. */ @@ -209,7 +210,23 @@ appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), result.copy(), op1.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + + if (ARM_Options.useOptimizedFlags) { + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + } + else { + //resolve overflow + OPT_RegisterOperand overflow = getFlag(Flag.Overflow); + OPT_RegisterOperand tmp1 = getTempInt(5); + OPT_RegisterOperand tmp2 = getTempInt(6); + OPT_RegisterOperand tmp_bool = gc.temps.makeTempBoolean(); + + appendInstruction(Binary.create(INT_SUB, tmp1.copyRO(), new OPT_IntConstantOperand(Integer.MAX_VALUE), op2.copy())); + appendInstruction(Binary.create(INT_SUB, tmp2.copyRO(), new OPT_IntConstantOperand(Integer.MIN_VALUE), op2.copy())); + appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, tmp_bool.copyRO(), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.GREATER_EQUAL(), new OPT_BranchProfileOperand(), op1.copy(), tmp1.copy(), OPT_ConditionOperand.GREATER(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, overflow.copyRO(), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS() , new OPT_BranchProfileOperand(), op1.copy(), tmp2.copy(), OPT_ConditionOperand.LESS(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(Binary.create(INT_OR, overflow.copyRO(), overflow.copy(), tmp_bool.copy())); + } } @Override @@ -223,9 +240,29 @@ @Override public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + + if (ARM_Options.useOptimizedFlags) { + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + } + else { + //resolve carry + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), op1.copy(), op2.copy(), OPT_ConditionOperand.LOWER().flipCode(), new OPT_BranchProfileOperand())); + + //resolve overflow + OPT_RegisterOperand overflow = getFlag(Flag.Overflow); + OPT_RegisterOperand tmp1 = getTempInt(5); + OPT_RegisterOperand tmp2 = getTempInt(6); + OPT_RegisterOperand tmp_bool = gc.temps.makeTempBoolean(); + + appendInstruction(Binary.create(INT_ADD, tmp1.copyRO(), new OPT_IntConstantOperand(Integer.MIN_VALUE), op2.copy())); + appendInstruction(Binary.create(INT_ADD, tmp2.copyRO(), new OPT_IntConstantOperand(Integer.MAX_VALUE), op2.copy())); + + appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, tmp_bool.copyRO(), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.GREATER_EQUAL(), new OPT_BranchProfileOperand(), op1.copy(), tmp1.copy(), OPT_ConditionOperand.LESS(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, overflow.copyRO(), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS() , new OPT_BranchProfileOperand(), op1.copy(), tmp2.copy(), OPT_ConditionOperand.GREATER(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(Binary.create(INT_OR, overflow.copyRO(), overflow.copy(), tmp_bool.copy())); + } } @Override @@ -237,6 +274,11 @@ public void onFlagWrite(Flag flag, ARM_Laziness lazy) { //nothing to do here, because the flags are already resolved } + + @Override + public void appendReverseSubFlags(ARM_Laziness lazy, OPT_RegisterOperand result, OPT_Operand op1, OPT_Operand op2) { + appendSubFlags(lazy, result, op2, op1); + } } /** Implements a flag behavior that will use lazy evaluation to only determine a flag value @@ -366,7 +408,13 @@ case LogicalOpAfterSub: case Sub: - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); + + if (ARM_Options.useOptimizedFlags) { + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); + } + else { + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), op1.copy(), op2.copy(), OPT_ConditionOperand.LOWER().flipCode(), new OPT_BranchProfileOperand())); + } break; default: @@ -382,12 +430,40 @@ switch (lazy.getOperation()) { case Add: case LogicalOpAfterAdd: - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + if (ARM_Options.useOptimizedFlags) { + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + } + else { + OPT_RegisterOperand tmp1 = getTempInt(5); + OPT_RegisterOperand tmp2 = getTempInt(6); + OPT_RegisterOperand tmp_bool = gc.temps.makeTempBoolean(); + + appendInstruction(Binary.create(INT_SUB, tmp1.copyRO(), new OPT_IntConstantOperand(Integer.MAX_VALUE), op2.copy())); + appendInstruction(Binary.create(INT_SUB, tmp2.copyRO(), new OPT_IntConstantOperand(Integer.MIN_VALUE), op2.copy())); + appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, tmp_bool.copyRO(), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.GREATER_EQUAL(), new OPT_BranchProfileOperand(), op1.copy(), tmp1.copy(), OPT_ConditionOperand.GREATER(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, getFlag(Flag.Overflow), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS() , new OPT_BranchProfileOperand(), op1.copy(), tmp2.copy(), OPT_ConditionOperand.LESS(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(Binary.create(INT_OR, getFlag(Flag.Overflow), getFlag(Flag.Overflow), tmp_bool.copy())); + } break; case Sub: case LogicalOpAfterSub: - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + if (ARM_Options.useOptimizedFlags) { + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + } + else { + //resolve overflow + OPT_RegisterOperand tmp1 = getTempInt(5); + OPT_RegisterOperand tmp2 = getTempInt(6); + OPT_RegisterOperand tmp_bool = gc.temps.makeTempBoolean(); + + appendInstruction(Binary.create(INT_ADD, tmp1.copyRO(), new OPT_IntConstantOperand(Integer.MIN_VALUE), op2.copy())); + appendInstruction(Binary.create(INT_ADD, tmp2.copyRO(), new OPT_IntConstantOperand(Integer.MAX_VALUE), op2.copy())); + + appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, tmp_bool.copyRO(), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.GREATER_EQUAL(), new OPT_BranchProfileOperand(), op1.copy(), tmp1.copy(), OPT_ConditionOperand.LESS(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, flagRegister, op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS() , new OPT_BranchProfileOperand(), op1.copy(), tmp2.copy(), OPT_ConditionOperand.GREATER(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(Binary.create(INT_OR, flagRegister.copyRO(), flagRegister.copy(), tmp_bool.copy())); + } break; default: @@ -416,6 +492,11 @@ public void onFlagWrite(Flag flag, ARM_Laziness lazy) { lazy.setValid(flag, true); } + + @Override + public void appendReverseSubFlags(ARM_Laziness lazy, OPT_RegisterOperand result, OPT_Operand op1, OPT_Operand op2) { + appendSubFlags(lazy, result, op2, op1); + } } @Override @@ -701,6 +782,12 @@ flagBehavior.appendSubFlags(lazy, result, op1, op2); } + + public void appendReverseSubFlags(ARM_Laziness lazy, OPT_RegisterOperand result, OPT_Operand lhs, OPT_Operand rhs) { + zeroUsed = negativeUsed = carryUsed = overflowUsed = true; + flagBehavior.appendReverseSubFlags(lazy, result, lhs, rhs); + } + public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { zeroUsed = negativeUsed = carryUsed = overflowUsed = true; flagBehavior.appendAddFlags(lazy, result, op1, op2); @@ -846,4 +933,5 @@ appendInstruction(BooleanCmp.create(OPT_Operators.BOOLEAN_CMP_INT, target, target, new OPT_IntConstantOperand(0), OPT_ConditionOperand.NOT_EQUAL(), new OPT_BranchProfileOperand())); } + } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-20 14:12:59 UTC (rev 168) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-20 21:08:34 UTC (rev 169) @@ -24,12 +24,15 @@ /** Set to true to enable a fastpath for the decoding of data processing instructions.. */ public final static boolean DATAPROCESSING_DECODER_FASTPATH = false; + + /** Shall ARM use the optimized BORROW_FROM_SUB() etc. operations? */ + public static boolean useOptimizedFlags = false; /** This variable describes, if the translated program shall be optimized using profiling information. */ public static boolean optimizeTranslationByProfiling = false; /** This variable describes, if the translated program shall be optimized using lazy evaluation.*/ - public static FlagBehaviour flagEvaluation = FlagBehaviour.Lazy; + public static FlagBehaviour flagEvaluation = FlagBehaviour.Immediate; /** Describes the default behaviour for dealing with ARM function calls and indirect jumps. */ public static InliningBehaviour inlining = InliningBehaviour.Default; @@ -47,7 +50,9 @@ inlining = ARM_Options.InliningBehaviour.valueOf(value); } else if (key.equalsIgnoreCase("memory")) { memoryModel = ARM_Options.MemoryModel.valueOf(value); - } + } else if (key.equalsIgnoreCase("optimizedFlags")) { + useOptimizedFlags = Boolean.parseBoolean(value); + } else { throw new Error("Unknown ARM option: " + key); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-20 14:12:59 UTC (rev 168) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-20 21:08:34 UTC (rev 169) @@ -843,22 +843,35 @@ case CC: //return !regs.isCarrySet(); - translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readCarryFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); + { + OPT_Operand carry = arm2ir.readCarryFlag(lazy); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, carry, OPT_ConditionOperand.NOT_EQUAL()); + } break; case CS: //return regs.isCarrySet(); - translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readCarryFlag(lazy), OPT_ConditionOperand.EQUAL()); + { + OPT_Operand carry = arm2ir.readCarryFlag(lazy); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, carry, OPT_ConditionOperand.EQUAL()); + } break; case EQ: //return regs.isZeroSet(); - translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readZeroFlag(lazy), OPT_ConditionOperand.EQUAL()); + { + OPT_Operand zero = arm2ir.readZeroFlag(lazy); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, zero, OPT_ConditionOperand.EQUAL()); + } break; case GE: //return regs.isNegativeSet() == regs.isOverflowSet(); - translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.EQUAL(), arm2ir.readOverflowFlag(lazy)); + { + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); + OPT_Operand negative = arm2ir.readNegativeFlag(lazy); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, negative, OPT_ConditionOperand.EQUAL(), overflow); + } break; case GT: @@ -879,17 +892,27 @@ case LT: //return regs.isNegativeSet() != regs.isOverflowSet(); - translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.readOverflowFlag(lazy)); + { + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); + OPT_Operand negative = arm2ir.readNegativeFlag(lazy); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, negative, OPT_ConditionOperand.NOT_EQUAL(), overflow); + } break; case MI: //return regs.isNegativeSet(); - translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.EQUAL()); + { + OPT_Operand negative = arm2ir.readNegativeFlag(lazy); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, negative, OPT_ConditionOperand.EQUAL()); + } break; case NE: //return !regs.isZeroSet(); - translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readZeroFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); + { + OPT_Operand zero = arm2ir.readZeroFlag(lazy); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, zero, OPT_ConditionOperand.NOT_EQUAL()); + } break; case NV: @@ -899,17 +922,26 @@ case PL: //return !regs.isNegativeSet(); - translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); + { + OPT_Operand negative = arm2ir.readNegativeFlag(lazy); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, negative, OPT_ConditionOperand.NOT_EQUAL()); + } break; case VC: //return !regs.isOverflowSet(); - translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readOverflowFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); + { + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, overflow, OPT_ConditionOperand.NOT_EQUAL()); + } break; case VS: //return regs.isOverflowSet(); - translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readOverflowFlag(lazy), OPT_ConditionOperand.EQUAL()); + { + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, overflow, OPT_ConditionOperand.EQUAL()); + } break; default: @@ -997,8 +1029,8 @@ private void translateCondition_GT(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return (regs.isNegativeSet() == regs.isOverflowSet()) && !regs.isZeroSet(); + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); OPT_Operand negative = arm2ir.readNegativeFlag(lazy); - OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); @@ -1010,8 +1042,8 @@ private void translateCondition_LE(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isZeroSet() || (regs.isNegativeSet() != regs.isOverflowSet()); + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); OPT_Operand negative = arm2ir.readNegativeFlag(lazy); - OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); @@ -1109,11 +1141,14 @@ } /** Sets the processor flags according to the result of subtracting <code>rhs</code> from <code>lhs</code>.*/ - protected final void setSubResult(OPT_RegisterOperand result, OPT_Operand lhs, OPT_Operand rhs) { + protected final void setSubResult(OPT_RegisterOperand result, OPT_Operand lhs, OPT_Operand rhs, boolean wasReverseSub) { if (i.updateConditionCodes) { if (i.Rd != ARM_Registers.PC) { - setSubFlags(result, lhs, rhs); + if (wasReverseSub) + setReverseSubFlags(result, lhs, rhs); + else + setSubFlags(result, lhs, rhs); } else { OPT_Instruction s = createCallToRegisters("restoreSPSR2CPSR", "()V", 0); @@ -1136,7 +1171,12 @@ arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(i.Rd), result.copy()) ); } } + + private void setReverseSubFlags(OPT_RegisterOperand result, OPT_Operand lhs, OPT_Operand rhs) { + arm2ir.appendReverseSubFlags(lazy, result, lhs, rhs); + } + /** * Sets the processor flags according to the result of a sub operation. * @param result @@ -1147,7 +1187,6 @@ * The sub's right-hand-side operator. */ protected final void setSubFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { - arm2ir.appendSubFlags(lazy, result, lhs, rhs); } @@ -1294,7 +1333,7 @@ arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2)); - setSubResult(result, operand1, operand2); + setSubResult(result, operand1, operand2, false); } } @@ -1313,7 +1352,7 @@ arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand2, operand1)); - setSubResult(result, operand2, operand1); + setSubResult(result, operand1, operand2, true); } } @@ -1385,7 +1424,7 @@ //Finally, subtract the second operands from the result arm2ir.setCurrentBlock(subWithoutCarry); arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2.copy())); - setSubResult(result, operand1, operand2); + setSubResult(result, operand1, operand2, false); } } @@ -2188,8 +2227,9 @@ return base; //add the offset to the base register + OPT_Operand offset = resolveOffset(); OPT_RegisterOperand tmp = arm2ir.getTempInt(0); - arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, base, resolveOffset())); + arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, base, offset)); if (i.isThumb && i.isLoad && i.Rn == ARM_Registers.PC) { //with thumb, bit 1 of the address is always ignored - address = address & 0xFFFFFFFC; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-20 14:13:04
|
Revision: 168 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=168&view=rev Author: michael_baer Date: 2007-08-20 07:12:59 -0700 (Mon, 20 Aug 2007) Log Message: ----------- - Fixed bug in IntAddressed Memory for 16bit unsigned loads - Renamed IntAddressedMemory to IntAddressedLittleEndian Memory - Renamed ByteAddressedMemory to ByteAddressedLittleEndian Memory Modified Paths: -------------- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java src/org/binarytranslator/generic/memory/ByteAddressedByteSwapMemory.java src/org/binarytranslator/generic/memory/IntAddressedByteSwapMemory.java src/org/binarytranslator/generic/memory/IntAddressedPreSwappedMemory.java Added Paths: ----------- src/org/binarytranslator/generic/memory/ByteAddressedLittleEndianMemory.java src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java Removed Paths: ------------- src/org/binarytranslator/generic/memory/ByteAddressedMemory.java src/org/binarytranslator/generic/memory/IntAddressedMemory.java Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-20 14:12:59 UTC (rev 168) @@ -10,8 +10,8 @@ import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.decoder.Interpreter; -import org.binarytranslator.generic.memory.ByteAddressedMemory; -import org.binarytranslator.generic.memory.IntAddressedMemory; +import org.binarytranslator.generic.memory.ByteAddressedLittleEndianMemory; +import org.binarytranslator.generic.memory.IntAddressedLittleEndianMemory; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; import org.binarytranslator.vmInterface.DBT_Trace; @@ -43,11 +43,11 @@ switch (ARM_Options.memoryModel) { case ByteAddressed: - memory = new ByteAddressedMemory(); + memory = new ByteAddressedLittleEndianMemory(); break; case IntAddressed: - memory = new IntAddressedMemory(); + memory = new IntAddressedLittleEndianMemory(); break; default: Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-20 14:12:59 UTC (rev 168) @@ -14,8 +14,8 @@ public class ARM_ImageProcessSpace extends ARM_ProcessSpace { private AngelSystemCalls sysCalls; - private final int STACK_SIZE = 4096 * 10; - private final int HEAP_SIZE = 4096 * 10; + private final int STACK_SIZE = 4096 * 100; + private final int HEAP_SIZE = 4096 * 100; public ARM_ImageProcessSpace() { super(); Modified: src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java 2007-08-20 14:12:59 UTC (rev 168) @@ -14,7 +14,7 @@ import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.os.process.ProcessSpace; -import org.binarytranslator.generic.memory.ByteAddressedMemory; +import org.binarytranslator.generic.memory.ByteAddressedLittleEndianMemory; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.execution.GdbController.GdbTarget; import org.binarytranslator.generic.fault.BadInstructionException; @@ -139,7 +139,7 @@ */ protected X86_ProcessSpace() { registers = new X86_Registers(); - memory = new ByteAddressedMemory(); + memory = new ByteAddressedLittleEndianMemory(); } /** Modified: src/org/binarytranslator/generic/memory/ByteAddressedByteSwapMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/ByteAddressedByteSwapMemory.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/generic/memory/ByteAddressedByteSwapMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -29,7 +29,7 @@ * .........00 |'H'| * </pre> */ -final public class ByteAddressedByteSwapMemory extends ByteAddressedMemory { +final public class ByteAddressedByteSwapMemory extends ByteAddressedLittleEndianMemory { /** * Constructor - used when this is the instatiated class */ Copied: src/org/binarytranslator/generic/memory/ByteAddressedLittleEndianMemory.java (from rev 149, src/org/binarytranslator/generic/memory/ByteAddressedMemory.java) =================================================================== --- src/org/binarytranslator/generic/memory/ByteAddressedLittleEndianMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/ByteAddressedLittleEndianMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -0,0 +1,550 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.fault.SegmentationFault; + +/** + * ByteAddressedMemory: + * + * Memory is arrays of bytes, no endian conversion is performed. + * + * The string helo followed by the int of 0xcafebabe appear as: + * + * <pre> + * Byte Address| + * ----------------- + * .........07 | ca| + * .........06 | fe| + * .........05 | ba| + * .........04 | be| + * .........03 |'o'| + * .........02 |'l'| + * .........01 |'e'| + * .........00 |'H'| + * </pre> + */ +public class ByteAddressedLittleEndianMemory extends CallBasedMemory { + + /** The size of a single page in bytes. */ + private static final int PAGE_SIZE = 4096; + + /** Bits in offset */ + private static final int OFFSET_BITS = 12; + + /** The number of pages */ + private static final int NUM_PAGES = 0x100000; + + /** The maximum amount of RAM available */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** The memory backing store */ + private byte readableMemory[][]; + private byte writableMemory[][]; + private byte executableMemory[][]; + + /** Do we have more optimal nio mmap operation? */ + private boolean HAVE_java_nio_FileChannelImpl_nio_mmap_file = false; + + /** + * Constructor - used when this is the instatiated class + */ + public ByteAddressedLittleEndianMemory() { + this(null); + } + + /** + * Constructor - used when deriving a class + * + * @param classType + * the name of the over-riding class + */ + protected ByteAddressedLittleEndianMemory(Class classType) { + super(classType != null ? classType : ByteAddressedLittleEndianMemory.class); + readableMemory = new byte[NUM_PAGES][]; + writableMemory = new byte[NUM_PAGES][]; + executableMemory = new byte[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + private static final int getOffset(int address) { + return address & (PAGE_SIZE - 1); + } + + /** + * Return the page table entry part of the address + */ + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if (getPage(i) == null) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if (getPage(i) != null) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + + // Create memory + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + byte pages[][] = new byte[num_pages][PAGE_SIZE]; + + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + + if (DBT_Options.debugMemory) { + System.out.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + // Allocate pages + readableMemory[pte + i] = read ? pages[i] : null; + writableMemory[pte + i] = write ? pages[i] : null; + executableMemory[pte + i] = exec ? pages[i] : null; + } + + return addr; + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + + // Check file offset is page aligned + /*if ((offset % PAGE_SIZE) != 0) { + MemoryMapException.unalignedFileOffset(offset); + }*/ + + // Calculate number of pages + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugMemory) { + System.out.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + try { + // Get page table entry + int pte = getPTE(addr); + // Can we optimise the reads to use mmap? + if (!HAVE_java_nio_FileChannelImpl_nio_mmap_file) { + // Sub-optimal + file.seek(offset); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + // Allocate page + byte page[] = new byte[PAGE_SIZE]; + if (i == 0) { // first read, start from offset upto a page length + file.read(page, getOffset(addr), PAGE_SIZE - getOffset(addr)); + } else if (i == (num_pages - 1)) { // last read + file.read(page, 0, ((len - getOffset(addr)) % PAGE_SIZE)); + } else { + file.read(page); + } + + readableMemory[pte + i] = read ? page : null; + writableMemory[pte + i] = write ? page : null; + executableMemory[pte + i] = exec ? page : null; + } + } else { + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + // Allocate page + if (read && write) { + readableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_WRITE, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + writableMemory[pte + i] = readableMemory[pte + i]; + if (exec) { + executableMemory[pte + i] = readableMemory[pte + i]; + } + } else if (read) { + readableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + if (exec) { + executableMemory[pte + i] = readableMemory[pte + i]; + } + } else if (exec) { + executableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + } else { + throw new Error("Unable to map address 0x" + + Integer.toHexString(addr) + " with permissions " + + (read ? "r" : "-") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + } + } + return addr; + } catch (java.io.IOException e) { + throw new Error(e); + } + } + + /** + * Returns the page currently mapped at the given page table entry. + * + * @param pte + * The page table entry, for which a page is to be retrieved. + * @return + * The page mapped at the given page table entry or null, if no page is currently mapped + * to that entry. + */ + private byte[] getPage(int pte) { + + if (readableMemory[pte] != null) + return readableMemory[pte]; + + if (writableMemory[pte] != null) + return writableMemory[pte]; + + if (executableMemory[pte] != null) + return executableMemory[pte]; + + return null; + } + + /** + * Unmap a page of memory + * + * @param addr + * the address to unmap + * @param len + * the amount of memory to unmap + */ + public void unmap(int addr, int len) { + for (int i = 0; i < len; i += PAGE_SIZE) { + + int pte = getPTE(addr + i); + if (getPage(pte) != null) { + readableMemory[pte] = null; + writableMemory[pte] = null; + executableMemory[pte] = null; + } + else { + throw new Error("Unmapping memory that's not mapped addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + } + } + + /** + * Is the given address mapped into memory? + * @param addr to check + * @return true => memory is mapped + */ + public boolean isMapped(int addr) { + return getPage(getPTE(addr)) != null; + } + + /** + * @return the size of a page + */ + public int getPageSize() { + return PAGE_SIZE; + } + + /** + * Is the given address aligned on a page boundary? + * + * @param addr + * the address to check + * @return whether the address is aligned + */ + public boolean isPageAligned(int addr) { + return (addr % PAGE_SIZE) == 0; + } + + /** + * Make the given address page aligned to the page beneath it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToPage(int addr) { + return (addr >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Make the given address page aligned to the page above it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToNextPage(int addr) { + return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Perform a byte load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + final public int loadSigned8(int addr) { + try { + if (DBT_Options.debugMemory) + System.err.println("LoadS8 address: 0x" + Integer.toHexString(addr) + + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); + return readableMemory[getPTE(addr)][getOffset(addr)]; + } catch (NullPointerException e) { + System.err.println("Null pointer exception at address: 0x" + + Integer.toHexString(addr)); + throw e; + } + } + + /** + * Perform a byte load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + final public int loadUnsigned8(int addr) { + try { + if (DBT_Options.debugMemory) + System.err.println("LoadU8 address: 0x" + Integer.toHexString(addr) + + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); + return readableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; + } catch (NullPointerException e) { + System.err.println("Null pointer exception at address: 0x" + + Integer.toHexString(addr)); + throw e; + } + } + + /** + * Perform a 16bit load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned16(int addr) { + return (loadSigned8(addr + 1) << 8) | loadUnsigned8(addr); + } + + /** + * Perform a 16bit load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned16(int addr) { + return (loadUnsigned8(addr + 1) << 8) | loadUnsigned8(addr); + } + + /** + * Perform a 32bit load + * + * @param addr + * the address of the value to load + * @return the result + */ + public int load32(int addr) { + try { + return (loadSigned8(addr + 3) << 24) | (loadUnsigned8(addr + 2) << 16) + | (loadUnsigned8(addr + 1) << 8) | loadUnsigned8(addr); + } catch (Exception e) { + throw new SegmentationFault(addr); + } + } + + /** + * Perform a 8bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction8(int addr) { + if (DBT_Options.debugMemory) + System.err.println("LoadI8 address: 0x" + Integer.toHexString(addr) + + " val: " + executableMemory[getPTE(addr)][getOffset(addr)]); + return executableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; + } + + /** + * Perform a 32bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction32(int addr) { + return (loadInstruction8(addr + 3) << 24) + | (loadInstruction8(addr + 2) << 16) + | (loadInstruction8(addr + 1) << 8) | loadInstruction8(addr); + } + + /** + * Perform a byte store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public final void store8(int addr, int value) { + if (DBT_Options.debugMemory) + System.err.println("Store8 address: 0x" + Integer.toHexString(addr) + + " val: 0x" + Integer.toHexString(value & 0xFF)); + writableMemory[getPTE(addr)][getOffset(addr)] = (byte) value; + } + + /** + * Perform a 16bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store16(int addr, int value) { + store8(addr + 1, value >> 8); + store8(addr, value); + } + + /** + * Perform a 32bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store32(int addr, int value) { + try { + store8(addr + 3, value >> 24); + store8(addr + 2, value >> 16); + store8(addr + 1, value >> 8); + store8(addr, value); + } catch (Exception e) { + throw new SegmentationFault(addr); + } + } + + @Override + public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { + + while (len > 0) { + int pte = getPTE(address); + byte[] page = getPage(pte); + + if (page == null) + throw new SegmentationFault(address); + + readableMemory[pte] = newRead ? page : null; + writableMemory[pte] = newWrite ? page : null; + executableMemory[pte] = newExec ? page : null; + + address += PAGE_SIZE; + len -= PAGE_SIZE; + } + } + + @Override + public int loadInstruction16(int addr) { + return (loadInstruction8(addr + 1) << 8) | loadInstruction8(addr); + } +} Deleted: src/org/binarytranslator/generic/memory/ByteAddressedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/ByteAddressedMemory.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/generic/memory/ByteAddressedMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -1,550 +0,0 @@ -/* - * This file is part of binarytranslator.org. The binarytranslator.org - * project is distributed under the Common Public License (CPL). - * A copy of the license is included in the distribution, and is also - * available at http://www.opensource.org/licenses/cpl1.0.php - * - * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 - */ -package org.binarytranslator.generic.memory; - -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; -import org.binarytranslator.DBT_Options; -import org.binarytranslator.generic.fault.SegmentationFault; - -/** - * ByteAddressedMemory: - * - * Memory is arrays of bytes, no endian conversion is performed. - * - * The string helo followed by the int of 0xcafebabe appear as: - * - * <pre> - * Byte Address| - * ----------------- - * .........07 | be| - * .........06 | ba| - * .........05 | fe| - * .........04 | ca| - * .........03 |'o'| - * .........02 |'l'| - * .........01 |'e'| - * .........00 |'H'| - * </pre> - */ -public class ByteAddressedMemory extends CallBasedMemory { - - /** The size of a single page in bytes. */ - private static final int PAGE_SIZE = 4096; - - /** Bits in offset */ - private static final int OFFSET_BITS = 12; - - /** The number of pages */ - private static final int NUM_PAGES = 0x100000; - - /** The maximum amount of RAM available */ - protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; - - /** The memory backing store */ - private byte readableMemory[][]; - private byte writableMemory[][]; - private byte executableMemory[][]; - - /** Do we have more optimal nio mmap operation? */ - private boolean HAVE_java_nio_FileChannelImpl_nio_mmap_file = false; - - /** - * Constructor - used when this is the instatiated class - */ - public ByteAddressedMemory() { - this(null); - } - - /** - * Constructor - used when deriving a class - * - * @param classType - * the name of the over-riding class - */ - protected ByteAddressedMemory(Class classType) { - super(classType != null ? classType : ByteAddressedMemory.class); - readableMemory = new byte[NUM_PAGES][]; - writableMemory = new byte[NUM_PAGES][]; - executableMemory = new byte[NUM_PAGES][]; - } - - /** - * Return the offset part of the address - */ - private static final int getOffset(int address) { - return address & (PAGE_SIZE - 1); - } - - /** - * Return the page table entry part of the address - */ - private static final int getPTE(int address) { - return address >>> OFFSET_BITS; - } - - /** - * Find free consecutive pages - * - * @param pages - * the number of pages required - * @return the address found - */ - private final int findFreePages(int pages) { - starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { - if (getPage(i) == null) { - int start = i; - int end = i + pages; - for (; i <= end; i++) { - if (getPage(i) != null) { - continue starting_page_search; - } - } - return start << OFFSET_BITS; - } - } - throw new Error( - "No mappable consecutive pages found for an anonymous map of size" - + (pages * PAGE_SIZE)); - } - - /** - * Map an anonymous page of memory - * - * @param addr - * the address to map or NULL if don't care - * @param len - * the amount of memory to map - * @param read - * is the page readable - * @param write - * is the page writable - * @param exec - * is the page executable - */ - public int map(int addr, int len, boolean read, boolean write, boolean exec) - throws MemoryMapException { - // Check address is page aligned - if ((addr % PAGE_SIZE) != 0) { - MemoryMapException.unalignedAddress(addr); - } - - // Create memory - int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; - byte pages[][] = new byte[num_pages][PAGE_SIZE]; - - // Find address if not specified - if (addr == 0) { - addr = findFreePages(num_pages); - } - - if (DBT_Options.debugMemory) { - System.out.println("Anonymous mapping: addr=0x" - + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") - + (write ? "w" : "-") + (exec ? "x" : "-")); - } - - // Get page table entry - int pte = getPTE(addr); - for (int i = 0; i < num_pages; i++) { - - // Check pages aren't already allocated - if (getPage(pte + i) != null) { - throw new Error("Memory map of already mapped location addr=0x" - + Integer.toHexString(addr) + " len=" + len); - } - - // Allocate pages - readableMemory[pte + i] = read ? pages[i] : null; - writableMemory[pte + i] = write ? pages[i] : null; - executableMemory[pte + i] = exec ? pages[i] : null; - } - - return addr; - } - - /** - * Map a page of memory from file - * - * @param file - * the file map in from - * @param addr - * the address to map or NULL if don't care - * @param len - * the amount of memory to map - * @param read - * is the page readable - * @param write - * is the page writable - * @param exec - * is the page executable - */ - public int map(RandomAccessFile file, long offset, int addr, int len, - boolean read, boolean write, boolean exec) throws MemoryMapException { - // Check address is page aligned - if ((addr % PAGE_SIZE) != 0) { - MemoryMapException.unalignedAddress(addr); - } - - // Check file offset is page aligned - /*if ((offset % PAGE_SIZE) != 0) { - MemoryMapException.unalignedFileOffset(offset); - }*/ - - // Calculate number of pages - int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; - // Find address if not specified - if (addr == 0) { - addr = findFreePages(num_pages); - } - if (DBT_Options.debugMemory) { - System.out.println("Mapping file " + file + " offset=" + offset - + " addr=0x" + Integer.toHexString(addr) + " len=" + len - + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); - } - try { - // Get page table entry - int pte = getPTE(addr); - // Can we optimise the reads to use mmap? - if (!HAVE_java_nio_FileChannelImpl_nio_mmap_file) { - // Sub-optimal - file.seek(offset); - for (int i = 0; i < num_pages; i++) { - // Check pages aren't already allocated - if (getPage(pte + i) != null) { - throw new Error("Memory map of already mapped location addr=0x" - + Integer.toHexString(addr) + " len=" + len); - } - // Allocate page - byte page[] = new byte[PAGE_SIZE]; - if (i == 0) { // first read, start from offset upto a page length - file.read(page, getOffset(addr), PAGE_SIZE - getOffset(addr)); - } else if (i == (num_pages - 1)) { // last read - file.read(page, 0, ((len - getOffset(addr)) % PAGE_SIZE)); - } else { - file.read(page); - } - - readableMemory[pte + i] = read ? page : null; - writableMemory[pte + i] = write ? page : null; - executableMemory[pte + i] = exec ? page : null; - } - } else { - for (int i = 0; i < num_pages; i++) { - // Check pages aren't already allocated - if (getPage(pte + i) != null) { - throw new Error("Memory map of already mapped location addr=0x" - + Integer.toHexString(addr) + " len=" + len); - } - - // Allocate page - if (read && write) { - readableMemory[pte + i] = file.getChannel().map( - FileChannel.MapMode.READ_WRITE, offset + (i * PAGE_SIZE), - PAGE_SIZE).array(); - writableMemory[pte + i] = readableMemory[pte + i]; - if (exec) { - executableMemory[pte + i] = readableMemory[pte + i]; - } - } else if (read) { - readableMemory[pte + i] = file.getChannel().map( - FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), - PAGE_SIZE).array(); - if (exec) { - executableMemory[pte + i] = readableMemory[pte + i]; - } - } else if (exec) { - executableMemory[pte + i] = file.getChannel().map( - FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), - PAGE_SIZE).array(); - } else { - throw new Error("Unable to map address 0x" - + Integer.toHexString(addr) + " with permissions " - + (read ? "r" : "-") + (write ? "w" : "-") + (exec ? "x" : "-")); - } - } - } - return addr; - } catch (java.io.IOException e) { - throw new Error(e); - } - } - - /** - * Returns the page currently mapped at the given page table entry. - * - * @param pte - * The page table entry, for which a page is to be retrieved. - * @return - * The page mapped at the given page table entry or null, if no page is currently mapped - * to that entry. - */ - private byte[] getPage(int pte) { - - if (readableMemory[pte] != null) - return readableMemory[pte]; - - if (writableMemory[pte] != null) - return writableMemory[pte]; - - if (executableMemory[pte] != null) - return executableMemory[pte]; - - return null; - } - - /** - * Unmap a page of memory - * - * @param addr - * the address to unmap - * @param len - * the amount of memory to unmap - */ - public void unmap(int addr, int len) { - for (int i = 0; i < len; i += PAGE_SIZE) { - - int pte = getPTE(addr + i); - if (getPage(pte) != null) { - readableMemory[pte] = null; - writableMemory[pte] = null; - executableMemory[pte] = null; - } - else { - throw new Error("Unmapping memory that's not mapped addr=0x" - + Integer.toHexString(addr) + " len=" + len); - } - } - } - - /** - * Is the given address mapped into memory? - * @param addr to check - * @return true => memory is mapped - */ - public boolean isMapped(int addr) { - return getPage(getPTE(addr)) != null; - } - - /** - * @return the size of a page - */ - public int getPageSize() { - return PAGE_SIZE; - } - - /** - * Is the given address aligned on a page boundary? - * - * @param addr - * the address to check - * @return whether the address is aligned - */ - public boolean isPageAligned(int addr) { - return (addr % PAGE_SIZE) == 0; - } - - /** - * Make the given address page aligned to the page beneath it - * - * @param addr - * the address to truncate - * @return the truncated address - */ - public int truncateToPage(int addr) { - return (addr >> OFFSET_BITS) << OFFSET_BITS; - } - - /** - * Make the given address page aligned to the page above it - * - * @param addr - * the address to truncate - * @return the truncated address - */ - public int truncateToNextPage(int addr) { - return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; - } - - /** - * Perform a byte load where the sign extended result fills the return value - * - * @param addr - * the address of the value to load - * @return the sign extended result - */ - final public int loadSigned8(int addr) { - try { - if (DBT_Options.debugMemory) - System.err.println("LoadS8 address: 0x" + Integer.toHexString(addr) - + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); - return readableMemory[getPTE(addr)][getOffset(addr)]; - } catch (NullPointerException e) { - System.err.println("Null pointer exception at address: 0x" - + Integer.toHexString(addr)); - throw e; - } - } - - /** - * Perform a byte load where the zero extended result fills the return value - * - * @param addr - * the address of the value to load - * @return the zero extended result - */ - final public int loadUnsigned8(int addr) { - try { - if (DBT_Options.debugMemory) - System.err.println("LoadU8 address: 0x" + Integer.toHexString(addr) - + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); - return readableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; - } catch (NullPointerException e) { - System.err.println("Null pointer exception at address: 0x" - + Integer.toHexString(addr)); - throw e; - } - } - - /** - * Perform a 16bit load where the sign extended result fills the return value - * - * @param addr - * the address of the value to load - * @return the sign extended result - */ - public int loadSigned16(int addr) { - return (loadSigned8(addr + 1) << 8) | loadUnsigned8(addr); - } - - /** - * Perform a 16bit load where the zero extended result fills the return value - * - * @param addr - * the address of the value to load - * @return the zero extended result - */ - public int loadUnsigned16(int addr) { - return (loadUnsigned8(addr + 1) << 8) | loadUnsigned8(addr); - } - - /** - * Perform a 32bit load - * - * @param addr - * the address of the value to load - * @return the result - */ - public int load32(int addr) { - try { - return (loadSigned8(addr + 3) << 24) | (loadUnsigned8(addr + 2) << 16) - | (loadUnsigned8(addr + 1) << 8) | loadUnsigned8(addr); - } catch (Exception e) { - throw new SegmentationFault(addr); - } - } - - /** - * Perform a 8bit load from memory that must be executable - * - * @param addr - * the address of the value to load - * @return the result - */ - public int loadInstruction8(int addr) { - if (DBT_Options.debugMemory) - System.err.println("LoadI8 address: 0x" + Integer.toHexString(addr) - + " val: " + executableMemory[getPTE(addr)][getOffset(addr)]); - return executableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; - } - - /** - * Perform a 32bit load from memory that must be executable - * - * @param addr - * the address of the value to load - * @return the result - */ - public int loadInstruction32(int addr) { - return (loadInstruction8(addr + 3) << 24) - | (loadInstruction8(addr + 2) << 16) - | (loadInstruction8(addr + 1) << 8) | loadInstruction8(addr); - } - - /** - * Perform a byte store - * - * @param value - * the value to store - * @param addr - * the address of where to store - */ - public final void store8(int addr, int value) { - if (DBT_Options.debugMemory) - System.err.println("Store8 address: 0x" + Integer.toHexString(addr) - + " val: 0x" + Integer.toHexString(value & 0xFF)); - writableMemory[getPTE(addr)][getOffset(addr)] = (byte) value; - } - - /** - * Perform a 16bit store - * - * @param value - * the value to store - * @param addr - * the address of where to store - */ - public void store16(int addr, int value) { - store8(addr + 1, value >> 8); - store8(addr, value); - } - - /** - * Perform a 32bit store - * - * @param value - * the value to store - * @param addr - * the address of where to store - */ - public void store32(int addr, int value) { - try { - store8(addr + 3, value >> 24); - store8(addr + 2, value >> 16); - store8(addr + 1, value >> 8); - store8(addr, value); - } catch (Exception e) { - throw new SegmentationFault(addr); - } - } - - @Override - public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { - - while (len > 0) { - int pte = getPTE(address); - byte[] page = getPage(pte); - - if (page == null) - throw new SegmentationFault(address); - - readableMemory[pte] = newRead ? page : null; - writableMemory[pte] = newWrite ? page : null; - executableMemory[pte] = newExec ? page : null; - - address += PAGE_SIZE; - len -= PAGE_SIZE; - } - } - - @Override - public int loadInstruction16(int addr) { - return (loadInstruction8(addr + 1) << 8) | loadInstruction8(addr); - } -} Modified: src/org/binarytranslator/generic/memory/IntAddressedByteSwapMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedByteSwapMemory.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/generic/memory/IntAddressedByteSwapMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -26,7 +26,7 @@ * .........00 |'H'|'e'|'l'|'l'| * </pre> */ -final public class IntAddressedByteSwapMemory extends IntAddressedMemory { +final public class IntAddressedByteSwapMemory extends IntAddressedLittleEndianMemory { /** * Constructor - used when this is the instatiated class */ Copied: src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java (from rev 164, src/org/binarytranslator/generic/memory/IntAddressedMemory.java) =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -0,0 +1,673 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; + +import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.fault.SegmentationFault; +import org.jikesrvm.VM_Configuration; +import org.vmmagic.pragma.Inline; + +/** + * IntAddressedMemory: + * + * Memory is arrays of ints, no endian conversion is performed. + * + * The string helloworld following by the int of 0xcafebabe appear as: + * + * <pre> + * Byte Address + * Int Address | 0 | 1 | 2 | 3 | + * ----------------------------- + * .........0c | be| ba| fe| ca| + * .........08 |'l'|'d'| \n| \0| + * .........04 |'o'|'W'|'o'|'r'| + * .........00 |'H'|'e'|'l'|'l'| + * </pre> + */ +public class IntAddressedLittleEndianMemory extends CallBasedMemory { + /** + * The size of pages + */ + protected static final int PAGE_SIZE = 4096; + + /** + * Bits in offset + */ + protected static final int OFFSET_BITS = 12; + + /** + * The number of pages + */ + protected static final int NUM_PAGES = 0x100000; + + /** + * The maximum amount of RAM available + */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** + * The memory backing store + */ + private int readableMemory[][]; + + private int writableMemory[][]; + + private int executableMemory[][]; + + /** + * Constructor - used when this is the instatiated class + */ + public IntAddressedLittleEndianMemory() { + this(null); + } + + /** + * Constructor - used when deriving a class + * + * @param classType + * the type of the over-riding class + */ + protected IntAddressedLittleEndianMemory(Class classType) { + super(classType != null ? classType : IntAddressedLittleEndianMemory.class); + readableMemory = new int[NUM_PAGES][]; + writableMemory = new int[NUM_PAGES][]; + executableMemory = new int[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + @Inline + protected int getOffset(int address) { + return (address & (PAGE_SIZE - 1)) >>> 2; + } + + /** + * Return the page table entry part of the address + */ + @Inline + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Is the given address mapped into memory? + * @param addr to check + * @return true => memory is mapped + */ + public boolean isMapped(int addr) { + return getPage(getPTE(addr)) != null; + } + + /** + * @return the size of a page + */ + public int getPageSize() { + return PAGE_SIZE; + } + + /** + * Is the given address aligned on a page boundary? + * + * @param addr + * the address to check + * @return whether the address is aligned + */ + public boolean isPageAligned(int addr) { + return (addr % PAGE_SIZE) == 0; + } + + /** + * Make the given address page aligned to the page beneath it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToPage(int addr) { + return (addr >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Make the given address page aligned to the page above it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToNextPage(int addr) { + return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if (getPage(i) == null) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if (getPage(i) != null) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check that the address is page aligned + if ((addr % PAGE_SIZE) != 0) { + // if it is not, truncate the address down to the next page boundary and + // start mapping from there + int validPageCount = addr / PAGE_SIZE; + int oldStartAddress = addr; + addr = validPageCount * PAGE_SIZE; + + if (DBT.VerifyAssertions) + DBT._assert(oldStartAddress > addr); + + // we have to map more more memory now to reach the same end address + len += (oldStartAddress - addr); + } + + // Calculate number of pages + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + // Create memory + int pages[][] = new int[num_pages][PAGE_SIZE / 4]; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugRuntime) { + System.out.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + readableMemory[pte+i] = read ? pages[i] : null; + writableMemory[pte+i] = write ? pages[i] : null; + executableMemory[pte+i] = exec ? pages[i] : null; + } + return addr; + } + + /** + * Returns the page currently mapped at the given page table entry. + * + * @param pte + * The page table entry, for which a page is to be retrieved. + * @return + * The page mapped at the given page table entry or null, if no page is currently mapped + * to that entry. + */ + private int[] getPage(int pte) { + + if (readableMemory[pte] != null) + return readableMemory[pte]; + + if (writableMemory[pte] != null) + return writableMemory[pte]; + + if (executableMemory[pte] != null) + return executableMemory[pte]; + + return null; + } + + @Override + public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { + + while (len > 0) { + int pte = getPTE(address); + int[] page = getPage(pte); + + if (page == null) + throw new SegmentationFault(address); + + readableMemory[pte] = newRead ? page : null; + writableMemory[pte] = newWrite ? page : null; + executableMemory[pte] = newExec ? page : null; + + address += PAGE_SIZE; + len -= PAGE_SIZE; + } + } + + /** + * Read an int from RandomAccessFile ensuring that a byte swap isn't performed + * + * @param file + * file to read from + * @return native endian read int + */ + protected int readInt(RandomAccessFile file) throws java.io.IOException { + if (VM_Configuration.BuildForPowerPC) { + return file.readInt(); // NB this will always read in big-endian format + } else { + return file.readUnsignedByte() | (file.readUnsignedByte() << 8) + | (file.readUnsignedByte() << 16) | (file.readByte() << 24); + } + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public final int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + // Check file offset is page aligned + /*if ((offset % PAGE_SIZE) != 0) { + MemoryMapException.unalignedFileOffset(offset); + }*/ + + if (DBT_Options.debugRuntime) { + System.out.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + addr = map(addr, len, read, write, exec); + + try { + file.seek(offset); + for (int i = 0; i < len; i += 4) { + + int[] page = getPage(getPTE(addr + i)); + page[getOffset(addr + i)] = readInt(file); + } + + return addr; + + } + catch (java.io.IOException e) { + throw new Error(e); + } + } + + /** + * Unmap a page of memory + * + * @param addr + * the address to unmap + * @param len + * the amount of memory to unmap + */ + public final void unmap(int addr, int len) { + for (int i = 0; i < len; i += PAGE_SIZE) { + + int pte = getPTE(addr + i); + + if (getPage(pte) != null) { + readableMemory[pte] = null; + writableMemory[pte] = null; + executableMemory[pte] = null; + } + else { + throw new Error("Unmapping memory that's not mapped addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + } + } + + /** + * Perform a 32bit load where addr is word aligned + * + * @param addr + * the address of the value to load + * @return the result + */ + protected final int loadWordAligned32(int addr) { + return readableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a 32bit load where addr is word aligned and executable + * + * @param addr + * the address of the value to load + * @return the result + */ + protected final int loadWordAlignedInstruction32(int addr) { + return executableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a byte load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned8(int addr) { + return (loadWordAligned32(addr) << ((3 - (addr & 0x3)) << 3)) >> 24; + // switch(addr & 3) { + // default: + // return (loadWordAligned32(addr) << 24) >> 24; + // case 1: + // return (loadWordAligned32(addr) << 16) >> 24; + // case 2: + // return (loadWordAligned32(addr) << 8) >> 24; + // case 3: + // return loadWordAligned32(addr) >> 24; + // } + } + + /** + * Perform a byte load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned8(int addr) { + return (loadWordAligned32(addr) >> ((addr & 3) << 3)) & 0xFF; + // switch(addr & 3) { + // default: + // return loadWordAligned32(addr) & 0xFF; + // case 1: + // return (loadWordAligned32(addr) >> 8) & 0xFF; + // case 2: + // return (loadWordAligned32(addr) >> 16) & 0xFF; + // case 3: + // return loadWordAligned32(addr) >>> 24; + // } + } + + /** + * Perform a 16bit load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned16(int addr) { + switch (addr & 3) { + default: + return (loadWordAligned32(addr) << 16) >> 16; + case 1: + return (loadWordAligned32(addr) << 8) >> 16; + case 2: + return loadWordAligned32(addr) >> 16; + case 3: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr) >>> 24) + | ((loadWordAligned32(addr + 1) << 24) >> 16); + } + } + + /** + * Perform a 16bit load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned16(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr) & 0xFFFF; + case 1: + return (loadWordAligned32(addr) >> 8) & 0xFFFF; + case 2: + return (loadWordAligned32(addr) >> 16) & 0xFFFF; + case 3: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr) >>> 24) + | ((loadWordAligned32(addr + 1) << 8) & 0xFF00); + } + } + + /** + * Perform a 32bit load + * + * @param addr + * the address of the value to load + * @return the result + */ + public int load32(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr); + case 1: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr + 3) & 0xFF) << 24) + | (loadWordAligned32(addr) >>> 8); + case 2: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr + 2) & 0xFFFF) << 16) + | (loadWordAligned32(addr) >>> 16); + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr + 1) & 0xFFFFFF) << 8) + | (loadWordAligned32(addr) >>> 24); + } + } + + /** + * Perform a 8bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction8(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr) & 0xFF; + case 1: + return (loadWordAlignedInstruction32(addr) >> 8) & 0xFF; + case 2: + return (loadWordAlignedInstruction32(addr) >> 16) & 0xFF; + case 3: + return loadWordAlignedInstruction32(addr) >>> 24; + } + } + + @Override + public int loadInstruction16(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr) >>> 16; + case 1: + return (loadWordAlignedInstruction32(addr) >> 8) & 0xFFFF; + case 2: + return loadWordAlignedInstruction32(addr) & 0xFFFF; + case 3: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr) >>> 24) + | ((loadWordAlignedInstruction32(addr + 1) << 8) & 0xFF00); + } + } + + /** + * Perform a 32bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction32(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr); + case 1: // 2 loads to deal with spanning int problem + return ((loadWordAlignedInstruction32(addr + 3) & 0xFF) << 24) + | (loadWordAlignedInstruction32(addr) >>> 8); + case 2: // 2 loads to deal with spanning int problem + return ((loadWordAlignedInstruction32(addr + 2) & 0xFFFF) << 16) + | (loadWordAlignedInstruction32(addr) >>> 16); + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAlignedInstruction32(addr + 1) & 0xFFFFFF) << 8) + | (loadWordAlignedInstruction32(addr) >>> 24); + } + } + + /** + * Perform a 32bit aligned store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + final protected void storeWordAligned32(int addr, int value) { + writableMemory[getPTE(addr)][getOffset(addr)] = value; + } + + /** + * Perform a 32bit load, from writable memory, where addr is word aligned + * + * @param addr + * the address of the value to load + * @return the result + */ + final protected int loadWordAligned32forWrite(int addr) { + return writableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a byte store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store8(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | (value & 0xFF)); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF00FF) + | ((value & 0xFF) << 8)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF00FFFF) + | ((value & 0xFF) << 16)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x00FFFFFF) + | (value << 24)); + break; + } + } + + /** + * Perform a 16bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store16(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF0000) + | (value & 0xFFFF)); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF0000FF) + | ((value & 0xFFFF) << 8)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x0000FFFF) + | (value << 16)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x00FFFFFF) + | (value << 24)); + storeWordAligned32(addr + 1, + (loadWordAligned32forWrite(addr + 1) & 0xFFFFFF00) + | ((value >> 8) & 0xFF)); + break; + } + } + + /** + * Perform a 32bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store32(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, value); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x000000FF) + | (value << 8)); + storeWordAligned32(addr + 3, + (loadWordAligned32forWrite(addr + 3) & 0xFFFFFF00) | (value >>> 24)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x0000FFFF) + | (value << 16)); + storeWordAligned32(addr + 2, + (loadWordAligned32forWrite(addr + 2) & 0xFFFF0000) | (value >>> 16)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x00FFFFFF) + | (value << 24)); + storeWordAligned32(addr + 1, + (loadWordAligned32forWrite(addr + 1) & 0xFF000000) | (value >>> 8)); + break; + } + } +} Deleted: src/org/binarytranslator/generic/memory/IntAddressedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedMemory.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/generic/memory/IntAddressedMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -1,673 +0,0 @@ -/* - * This file is part of binarytranslator.org. The binarytranslator.org - * project is distributed under the Common Public License (CPL). - * A copy of the license is included in the distribution, and is also - * available at http://www.opensource.org/licenses/cpl1.0.php - * - * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 - */ -package org.bi... [truncated message content] |
From: <mic...@us...> - 2007-08-15 16:24:04
|
Revision: 167 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=167&view=rev Author: michael_baer Date: 2007-08-15 09:24:05 -0700 (Wed, 15 Aug 2007) Log Message: ----------- - Controlling ARM memory model using a command line paremter - added new option to disable pearcolator inlining Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-15 11:08:41 UTC (rev 166) +++ src/org/binarytranslator/DBT_Options.java 2007-08-15 16:24:05 UTC (rev 167) @@ -175,25 +175,12 @@ } else if (key.startsWith("arm:")) { key = key.substring(4); - parseArmOption(key, value); + ARM_Options.parseOption(key, value); } else { throw new Error("Unknown argument."); } } - - private static void parseArmOption(String key, String value) { - if (key.equalsIgnoreCase("optimizeByProfiling")) { - ARM_Options.optimizeTranslationByProfiling = Boolean.parseBoolean(value); - } else if (key.equalsIgnoreCase("flagEvaluation")) { - ARM_Options.flagEvaluation = ARM_Options.FlagBehaviour.valueOf(value); - } else if (key.equalsIgnoreCase("inline")) { - ARM_Options.inlining = ARM_Options.InliningBehaviour.valueOf(value); - } - else { - throw new Error("Unknown ARM option: " + key); - } - } private static void parseDbtOption(String key, String value) { if (key.equalsIgnoreCase("debugInstr")) { Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-15 11:08:41 UTC (rev 166) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-15 16:24:05 UTC (rev 167) @@ -468,6 +468,9 @@ switch (ARM_Options.inlining) { + case NoInlining: + return false; + case Default: return super.inlineBranchInstruction(targetPc, jump); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-15 11:08:41 UTC (rev 166) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-15 16:24:05 UTC (rev 167) @@ -8,6 +8,7 @@ } public enum InliningBehaviour { + NoInlining, Default, Functions, FunctionCalls, @@ -16,6 +17,11 @@ All, } + public enum MemoryModel { + IntAddressed, + ByteAddressed + } + /** Set to true to enable a fastpath for the decoding of data processing instructions.. */ public final static boolean DATAPROCESSING_DECODER_FASTPATH = false; @@ -27,4 +33,23 @@ /** Describes the default behaviour for dealing with ARM function calls and indirect jumps. */ public static InliningBehaviour inlining = InliningBehaviour.Default; + + /** Sets the memory model that ARM shall use. */ + public static MemoryModel memoryModel = MemoryModel.IntAddressed; + + + public static void parseOption(String key, String value) { + if (key.equalsIgnoreCase("optimizeByProfiling")) { + optimizeTranslationByProfiling = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("flagEvaluation")) { + flagEvaluation = ARM_Options.FlagBehaviour.valueOf(value); + } else if (key.equalsIgnoreCase("inline")) { + inlining = ARM_Options.InliningBehaviour.valueOf(value); + } else if (key.equalsIgnoreCase("memory")) { + memoryModel = ARM_Options.MemoryModel.valueOf(value); + } + else { + throw new Error("Unknown ARM option: " + key); + } + } } Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-15 11:08:41 UTC (rev 166) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-15 16:24:05 UTC (rev 167) @@ -5,10 +5,12 @@ import org.binarytranslator.arch.arm.decoder.ARM2IR; import org.binarytranslator.arch.arm.decoder.ARM_Disassembler; import org.binarytranslator.arch.arm.decoder.ARM_Interpreter; +import org.binarytranslator.arch.arm.decoder.ARM_Options; import org.binarytranslator.arch.arm.os.process.image.ARM_ImageProcessSpace; import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.memory.ByteAddressedMemory; import org.binarytranslator.generic.memory.IntAddressedMemory; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; @@ -38,7 +40,20 @@ protected ARM_ProcessSpace() { registers = new ARM_Registers(); - memory = new IntAddressedMemory(); + + switch (ARM_Options.memoryModel) { + case ByteAddressed: + memory = new ByteAddressedMemory(); + break; + + case IntAddressed: + memory = new IntAddressedMemory(); + break; + + default: + throw new RuntimeException("Unexpected ARM memory model setting: " + ARM_Options.memoryModel); + } + } /** This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-15 11:08:39
|
Revision: 166 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=166&view=rev Author: michael_baer Date: 2007-08-15 04:08:41 -0700 (Wed, 15 Aug 2007) Log Message: ----------- - Disabled debug output by default - added options to show arm stack and heap range Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-14 17:25:25 UTC (rev 165) +++ src/org/binarytranslator/DBT_Options.java 2007-08-15 11:08:41 UTC (rev 166) @@ -25,11 +25,8 @@ public final static boolean buildForSunVM = false; /** Enable the profiling of application during interpretation? */ - public final static boolean profileDuringInterpretation = false; + public final static boolean profileDuringInterpretation = true; - /** Debug binary loading */ - public final static boolean debugLoader = true; - /** Are unimplemented system calls fatal? */ public final static boolean unimplementedSystemCallsFatal = false; @@ -77,38 +74,41 @@ public final static boolean eliminateRegisterFills = true; /** Print dissassembly of translated instructions. */ - public static boolean debugInstr = true; + public static boolean debugInstr = false; /** Print information about the lazy resolution of branch addresses...*/ - public static boolean debugBranchResolution = true; + public static boolean debugBranchResolution = false; /** During code translation, print information about the creation of basic blocks. */ public final static boolean debugCFG = false; - - /** Debug using GDB? */ - public static boolean gdbStub = false; - - /** GDB stub port */ - public static int gdbStubPort = 1234; - /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ - public static int minTraceValue = 20; + /** Debug binary loading */ + public static boolean debugLoader = false; /** Print debug information during the translation of instructions. */ - public static boolean debugTranslation = true; + public static boolean debugTranslation = false; /** In ProcessSpace, print syscall numbers. */ - public static boolean debugSyscall = true; + public static boolean debugSyscalls = false; /** In ProcessSpace, print syscall numbers. */ - public static boolean debugSyscallMore = false; + public static boolean debugSyscallsMore = false; /** Print out various messages about the emulator starting. */ - public static boolean debugRuntime = true; + public static boolean debugRuntime = false; /** Print out messages from the memory system */ public static boolean debugMemory = false; + + /** Debug using GDB? */ + public static boolean gdbStub = false; + + /** GDB stub port */ + public static int gdbStubPort = 1234; + /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ + public static int minTraceValue = 20; + /** Inline calls to descendents of callbased memory? */ public static boolean inlineCallbasedMemory = false; @@ -204,12 +204,14 @@ debugBranchResolution = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("debugMemory")) { debugMemory = Boolean.parseBoolean(value); - } else if (key.equalsIgnoreCase("debugSyscall")) { - debugSyscall = Boolean.parseBoolean(value); - } else if (key.equalsIgnoreCase("debugSyscallMore")) { - debugSyscallMore = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("debugSyscalls")) { + debugSyscalls = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("debugSyscallsMore")) { + debugSyscallsMore = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("debugTranslation")) { debugTranslation = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("debugLoader")) { + debugLoader = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("instrOpt0")) { instrOpt0 = Integer.parseInt(value); } else if (key.equalsIgnoreCase("instrOpt1")) { Modified: src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-14 17:25:25 UTC (rev 165) +++ src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-15 11:08:41 UTC (rev 166) @@ -107,7 +107,7 @@ public void doSysCall(int callNum) { try { - if (DBT_Options.debugSyscall) + if (DBT_Options.debugSyscalls) System.out.println("Executing Angel Syscall: " + callNum); sysCalls[callNum].execute(); @@ -310,7 +310,7 @@ String fileName = readString(ptrBuffer, length); - if (DBT_Options.debugSyscallMore) + if (DBT_Options.debugSyscallsMore) System.out.println("Opening file: " + fileName); try { Modified: src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java =================================================================== --- src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java 2007-08-14 17:25:25 UTC (rev 165) +++ src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java 2007-08-15 11:08:41 UTC (rev 166) @@ -187,7 +187,7 @@ public void doSysCall() { int sysCallNumber = src.getSysCallNumber(); - if (DBT_Options.debugSyscall) + if (DBT_Options.debugSyscalls) System.err.println("Syscall " + sysCallToString(sysCallNumber)); arguments = src.getSysCallArguments(); @@ -357,7 +357,7 @@ // accordingly. args[0] points to the file name. String fileName = memoryReadString(pathname); - if (DBT_Options.debugSyscall) + if (DBT_Options.debugSyscalls) System.err.println("Program tries to open: " + fileName); FileMode mode; @@ -527,7 +527,7 @@ String filename = memoryReadString(ptrFilename); - if (DBT_Options.debugSyscallMore) + if (DBT_Options.debugSyscallsMore) System.err.println("Stat64() denies existance of file: " + filename); src.setSysCallError(errno.ENOENT); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-14 17:25:21
|
Revision: 165 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=165&view=rev Author: michael_baer Date: 2007-08-14 10:25:25 -0700 (Tue, 14 Aug 2007) Log Message: ----------- - Fixed bug with overlapping translator registers during MultiplyAccumulate - Check in missing file from last commit Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java Added Paths: ----------- src/org/binarytranslator/generic/fault/InsufficientMemoryException.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-14 15:32:09 UTC (rev 164) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-14 17:25:25 UTC (rev 165) @@ -1955,12 +1955,16 @@ OPT_RegisterOperand result = arm2ir.getRegister(i.Rd); //calculate the result - arm2ir.appendInstruction(Binary.create(INT_MUL, result, operand1, operand2)); - if (i.accumulate) { + OPT_RegisterOperand tmp = arm2ir.getTempInt(0); + arm2ir.appendInstruction(Binary.create(INT_MUL, tmp, operand1, operand2)); + OPT_Operand operand3 = arm2ir.getRegister(i.Rn); - arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), result.copy(), operand3)); + arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), tmp.copy(), operand3)); } + else { + arm2ir.appendInstruction(Binary.create(INT_MUL, result, operand1, operand2)); + } if (i.updateConditionCodes) { //set the negative & zero flag Modified: src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-14 15:32:09 UTC (rev 164) +++ src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-14 17:25:25 UTC (rev 165) @@ -665,7 +665,7 @@ } writeString(cmdLine, ptrBuffer); - ps.memory.store32(ptrParamBlock + 4, cmdLine.length() + 1); + ps.memory.store32(ptrParamBlock + 4, cmdLine.length()); setReturn(0); } } Added: src/org/binarytranslator/generic/fault/InsufficientMemoryException.java =================================================================== --- src/org/binarytranslator/generic/fault/InsufficientMemoryException.java (rev 0) +++ src/org/binarytranslator/generic/fault/InsufficientMemoryException.java 2007-08-14 17:25:25 UTC (rev 165) @@ -0,0 +1,20 @@ +package org.binarytranslator.generic.fault; + +import org.binarytranslator.generic.os.process.ProcessSpace; + +/** + * Thrown when a process space runs out of (virtual) memory when performing an operation. + * + */ +public class InsufficientMemoryException extends RuntimeException { + private final String operation; + + public InsufficientMemoryException(ProcessSpace ps, String operation) { + this.operation = operation; + } + + @Override + public String toString() { + return "InsufficientMemoryException (Operation: " + operation + ")"; + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-14 15:32:08
|
Revision: 164 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=164&view=rev Author: michael_baer Date: 2007-08-14 08:32:09 -0700 (Tue, 14 Aug 2007) Log Message: ----------- - Various smaller performance fixes - Added functions to inline a call to CodeTranslator Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/arch/ppc/decoder/PPC2IR.java src/org/binarytranslator/arch/ppc/os/process/PPC_ProcessSpace.java src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java src/org/binarytranslator/generic/decoder/CodeTranslator.java src/org/binarytranslator/generic/execution/StagedEmulationController.java src/org/binarytranslator/generic/memory/CallBasedMemory.java src/org/binarytranslator/generic/memory/IntAddressedMemory.java src/org/binarytranslator/generic/memory/IntAddressedPreSwappedMemory.java src/org/binarytranslator/generic/os/loader/elf/ELF_File.java src/org/binarytranslator/generic/os/process/ProcessSpace.java src/org/binarytranslator/vmInterface/DBT_Trace.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/DBT_Options.java 2007-08-14 15:32:09 UTC (rev 164) @@ -108,6 +108,9 @@ /** Print out messages from the memory system */ public static boolean debugMemory = false; + + /** Inline calls to descendents of callbased memory? */ + public static boolean inlineCallbasedMemory = false; /** The user ID for the user running the command */ public final static int UID = 1000; @@ -184,7 +187,7 @@ ARM_Options.optimizeTranslationByProfiling = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("flagEvaluation")) { ARM_Options.flagEvaluation = ARM_Options.FlagBehaviour.valueOf(value); - } else if (key.equalsIgnoreCase("inlining")) { + } else if (key.equalsIgnoreCase("inline")) { ARM_Options.inlining = ARM_Options.InliningBehaviour.valueOf(value); } else { @@ -229,6 +232,8 @@ saveProfileToFile = value; } else if (key.equalsIgnoreCase("minTraceValue")) { minTraceValue = Integer.parseInt(value); + } else if (key.equalsIgnoreCase("inlineCallbasedMemory")) { + inlineCallbasedMemory = Boolean.parseBoolean(value); } else { throw new Error("Unknown DBT option: " + key); Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/Main.java 2007-08-14 15:32:09 UTC (rev 164) @@ -85,6 +85,10 @@ System.err.println("The specified executable '" + DBT_Options.executableFile + "' could not be found."); return; } + + if (DBT.VerifyAssertions) { + System.err.println("WARNING: Assertions are enabled."); + } try { report("Loading " + DBT_Options.executableFile); Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-14 15:32:09 UTC (rev 164) @@ -477,12 +477,27 @@ else return super.inlineBranchInstruction(targetPc, jump); + case FunctionCalls: + if (jump.type == BranchType.CALL) + return true; + else + return super.inlineBranchInstruction(targetPc, jump); + + case FunctionReturns: + if (jump.type == BranchType.CALL) + return true; + else + return super.inlineBranchInstruction(targetPc, jump); + case Functions: if (jump.type == BranchType.CALL || jump.type == BranchType.RETURN) return true; else return super.inlineBranchInstruction(targetPc, jump); + case All: + return true; + default: throw new RuntimeException("Unexpected inlining type."); } @@ -782,6 +797,9 @@ * The operand which is to be rotated. * @param rotation * The amount of rotation that is to be applied to the operand. + * + * @param inline + * Shall the invokation of this rotate right be inlined? */ public void appendRotateRight(OPT_RegisterOperand result, OPT_Operand rotatedOperand, OPT_Operand rotation) { VM_TypeReference IntegerType = VM_TypeReference Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-08-14 15:32:09 UTC (rev 164) @@ -374,7 +374,7 @@ /** The successor of this instruction, if the condition evaluates to false.*/ private final int conditionFalseSuccessor; - /** The address of the successor of this instrction if it is constant, otherwise -1. */ + /** The address of the successor of this instruction if it is constant, otherwise -1. */ private final int successorInstruction; /** The address of this instruction. */ @@ -406,7 +406,10 @@ } if (successorInstruction != -1) { - ps.branchInfo.profileBranch(instructionAddress, conditionTrueSuccessor); + if (conditionTrueSuccessor == conditionFalseSuccessor) + ps.branchInfo.profileBranch(instructionAddress, instructionAddress); + else + ps.branchInfo.profileBranch(instructionAddress, conditionTrueSuccessor); } } else { Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-14 15:32:09 UTC (rev 164) @@ -10,7 +10,10 @@ public enum InliningBehaviour { Default, Functions, - DynamicJumps + FunctionCalls, + FunctionReturns, + DynamicJumps, + All, } /** Set to true to enable a fastpath for the decoding of data processing instructions.. */ @@ -22,5 +25,6 @@ /** This variable describes, if the translated program shall be optimized using lazy evaluation.*/ public static FlagBehaviour flagEvaluation = FlagBehaviour.Lazy; + /** Describes the default behaviour for dealing with ARM function calls and indirect jumps. */ public static InliningBehaviour inlining = InliningBehaviour.Default; } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-14 15:32:09 UTC (rev 164) @@ -764,7 +764,7 @@ */ private float getSkipProbability() { - if (ARM_Options.optimizeTranslationByProfiling) + if (!ARM_Options.optimizeTranslationByProfiling) return -1f; return ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); @@ -1279,7 +1279,7 @@ } } - /** Subtract. <code>Rd = op1 - op2 </code>.*/ + /** Subtract. <code>Rd = op1 - op2</code>.*/ private final class DataProcessing_Sub extends DataProcessing { public DataProcessing_Sub(ARM_Instructions.DataProcessing instr) { Modified: src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-14 15:32:09 UTC (rev 164) @@ -48,6 +48,18 @@ /** The directory in which temporary files are created. Note that the path is expected to end with a path delimiter.*/ private final static String TEMP_FILE_DIR = "/tmp/"; + /** The first address on the heap. */ + private int heapBegin; + + /** The last address on the heap. */ + private int heapEnd; + + /** The first address on the stack. */ + private int stackBegin; + + /** The last address on the stack*/ + private int stackEnd; + /** The file handle that is distributed with the next call to {@link #addFile(RandomAccessFile)}. * Valid Angle handles are non-zero values (i.e. >= 1).*/ private int nextFileHandle = 1; @@ -55,7 +67,7 @@ /** */ private AngelSystemCall[] sysCalls; - public AngelSystemCalls(ARM_ProcessSpace ps) { + public AngelSystemCalls(ARM_ProcessSpace ps, int heapBegin, int heapEnd, int stackBegin, int stackEnd) { this.ps = ps; sysCalls = new AngelSystemCall[0x32]; @@ -84,6 +96,12 @@ sysCalls[0x18] = new Sys_Exit(); sysCalls[0x30] = new Sys_Elapsed(); sysCalls[0x31] = new Sys_TickFreq(); + + this.heapBegin = heapBegin; + this.heapEnd = heapEnd; + + this.stackBegin = stackBegin; + this.stackEnd = stackEnd; } public void doSysCall(int callNum) { @@ -128,7 +146,7 @@ } } - private interface AngelFileStream { + private static interface AngelFileStream { boolean isTty(); int getLength(); @@ -143,7 +161,7 @@ void seek(long pos) throws IOException; } - private class ConsoleStream implements AngelFileStream { + private static class ConsoleStream implements AngelFileStream { private String previousInputLine = null; @@ -203,7 +221,7 @@ } } - private class FileStream implements AngelFileStream { + private static class FileStream implements AngelFileStream { private final RandomAccessFile file; @@ -630,11 +648,11 @@ String cmdLine = DBT_Options.executableFile; - if (cmdLine.contains(" ")) + if (cmdLine.contains(" ") && !cmdLine.contains("\"")) cmdLine = '"' + cmdLine + '"'; for(String s : DBT_Options.executableArguments) { - if (s.contains(" ")) { + if (s.contains(" ") && !s.contains("\"")) { s = '"' + s + '"'; } @@ -659,10 +677,10 @@ int ptrParamBlock = ps.registers.get(1); //return that we couldn't calculate any of the requested heap size values - ps.memory.store32(ptrParamBlock, 0); - ps.memory.store32(ptrParamBlock + 4, 0); - ps.memory.store32(ptrParamBlock + 8, 0); - ps.memory.store32(ptrParamBlock + 12, 0); + ps.memory.store32(ptrParamBlock, heapBegin); + ps.memory.store32(ptrParamBlock + 4, heapEnd); + ps.memory.store32(ptrParamBlock + 8, stackBegin); + ps.memory.store32(ptrParamBlock + 12, stackEnd); } } Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-14 15:32:09 UTC (rev 164) @@ -9,7 +9,7 @@ import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.decoder.Interpreter; -import org.binarytranslator.generic.memory.ByteAddressedMemory; +import org.binarytranslator.generic.memory.IntAddressedMemory; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; import org.binarytranslator.vmInterface.DBT_Trace; @@ -38,7 +38,7 @@ protected ARM_ProcessSpace() { registers = new ARM_Registers(); - memory = new ByteAddressedMemory(); + memory = new IntAddressedMemory(); } /** @@ -49,6 +49,7 @@ * the generation context for the HIR generation * @return a HIR generator */ + @Override public CodeTranslator createTranslator(OPT_GenerationContext context, DBT_Trace trace) { return new ARM2IR(context, trace); } Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-14 15:32:09 UTC (rev 164) @@ -1,26 +1,55 @@ package org.binarytranslator.arch.arm.os.process.image; import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; import org.binarytranslator.arch.arm.decoder.ARM_InstructionDecoder; import org.binarytranslator.arch.arm.decoder.ARM_Instructions; import org.binarytranslator.arch.arm.os.abi.semihosting.AngelSystemCalls; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.generic.execution.GdbController.GdbTarget; -import org.binarytranslator.generic.memory.AutoMappingMemory; +import org.binarytranslator.generic.fault.InsufficientMemoryException; import org.binarytranslator.generic.os.loader.Loader; public class ARM_ImageProcessSpace extends ARM_ProcessSpace { - private AngelSystemCalls sysCalls = new AngelSystemCalls(this); + private AngelSystemCalls sysCalls; + private final int STACK_SIZE = 4096 * 10; + private final int HEAP_SIZE = 4096 * 10; public ARM_ImageProcessSpace() { super(); //make sure that pages of memory are automatically mapped in as they are requested. - memory = new AutoMappingMemory(memory); + //memory = new AutoMappingMemory(memory); } + private int allocateFreeMemoryArea(int stackSize) throws InsufficientMemoryException + { + int pagesize = memory.getPageSize(); + int stackStart = -1; + int checkedAddress = stackStart; + + while (checkedAddress < 0 || checkedAddress > pagesize) { + if (memory.isMapped(checkedAddress)) { + //we cannot extend the stack into this page + stackStart = checkedAddress - pagesize; + } + else { + int stackspace = Math.abs(stackStart - checkedAddress) + pagesize; + + if (stackspace >= stackSize) { + memory.ensureMapped(stackStart - stackSize + 1, stackStart); + return stackStart - stackSize + 1; + } + } + + checkedAddress -= pagesize; + } + + throw new InsufficientMemoryException(this, "Allocate free memory area for ARM stack and heap."); + } + @Override public void doSysCall() { @@ -91,6 +120,15 @@ @Override public void initialise(Loader loader) { registers.set(ARM_Registers.PC, loader.getEntryPoint()); + int stackBegin = allocateFreeMemoryArea(STACK_SIZE); + int heapBegin = allocateFreeMemoryArea(HEAP_SIZE); + + if (DBT_Options.debugMemory || DBT_Options.debugLoader) { + System.out.println(String.format("Placing ARM Heap from 0x%x to 0x%x.", heapBegin, heapBegin + HEAP_SIZE - 1)); + System.out.println(String.format("Placing ARM Stack from 0x%x to 0x%x.", stackBegin, stackBegin + STACK_SIZE - 1)); + } + + sysCalls = new AngelSystemCalls(this, heapBegin, heapBegin + HEAP_SIZE, stackBegin, stackBegin + STACK_SIZE); } } Modified: src/org/binarytranslator/arch/ppc/decoder/PPC2IR.java =================================================================== --- src/org/binarytranslator/arch/ppc/decoder/PPC2IR.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/arch/ppc/decoder/PPC2IR.java 2007-08-14 15:32:09 UTC (rev 164) @@ -29,6 +29,7 @@ import org.jikesrvm.compilers.opt.ir.OPT_AddressConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; import org.jikesrvm.compilers.opt.ir.OPT_HIRGenerator; +import org.jikesrvm.compilers.opt.ir.OPT_IR; import org.jikesrvm.compilers.opt.ir.OPT_IntConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_LocationOperand; import org.jikesrvm.compilers.opt.ir.OPT_Operators; @@ -272,6 +273,18 @@ report("CFG at end of constructor:\n" + gc.cfg); } } + + /** + * Should a trace follow a branch and link instruction or should it terminate + * the trace? + * + * @param pc + * the address of the branch and link instruction + * @return whether the trace should continue + */ + public boolean traceContinuesAfterBranchAndLink(int pc) { + return shallTraceStop() == false; + } /** * Translate the instruction at the given pc Modified: src/org/binarytranslator/arch/ppc/os/process/PPC_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/ppc/os/process/PPC_ProcessSpace.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/arch/ppc/os/process/PPC_ProcessSpace.java 2007-08-14 15:32:09 UTC (rev 164) @@ -140,6 +140,7 @@ * the generation context for the HIR generation * @return a HIR generator */ + @Override public CodeTranslator createTranslator(OPT_GenerationContext context, DBT_Trace trace) { return new PPC2IR(context, trace); } Modified: src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java 2007-08-14 15:32:09 UTC (rev 164) @@ -12,7 +12,6 @@ import java.util.Hashtable; import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; - import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.os.process.ProcessSpace; import org.binarytranslator.generic.memory.ByteAddressedMemory; @@ -149,6 +148,7 @@ * @param context the generation context for the HIR generation * @return a HIR generator */ + @Override public CodeTranslator createTranslator(OPT_GenerationContext context, DBT_Trace trace) { return new X862IR(context, trace); } Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-14 15:32:09 UTC (rev 164) @@ -29,6 +29,7 @@ import org.jikesrvm.classloader.VM_MethodReference; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.opt.OPT_Constants; +import org.jikesrvm.compilers.opt.OPT_InlineDecision; import org.jikesrvm.compilers.opt.ir.Athrow; import org.jikesrvm.compilers.opt.ir.BBend; import org.jikesrvm.compilers.opt.ir.Call; @@ -45,6 +46,7 @@ import org.jikesrvm.compilers.opt.ir.OPT_ConditionOperand; import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; import org.jikesrvm.compilers.opt.ir.OPT_HIRGenerator; +import org.jikesrvm.compilers.opt.ir.OPT_Inliner; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import org.jikesrvm.compilers.opt.ir.OPT_IntConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_MethodOperand; @@ -130,7 +132,7 @@ public final ProcessSpace ps; /** The VM method's generation context. */ - protected OPT_GenerationContext gc; + protected final OPT_GenerationContext gc; /** The OPT_BasicBlock in which instructions are currently being inserted */ protected OPT_BasicBlock currentBlock; @@ -208,7 +210,7 @@ * @param context * The JRVM generation context for this trace. */ - protected CodeTranslator(OPT_GenerationContext context, + protected CodeTranslator(OPT_GenerationContext context, DBT_Trace trace) { // Store the trace that we're invoked from @@ -284,7 +286,12 @@ printNextBlocks(preFillBlock, 50); } + try { ((DBT_Trace) gc.method).setNumberOfInstructions(numberOfInstructions); + } + catch (ClassCastException e) { + System.err.println("Error casting " + gc.method + " to DBT_Trace."); + } } @@ -531,7 +538,7 @@ /** * Get the generation context. */ - public OPT_GenerationContext getGenerationContext() { + public final OPT_GenerationContext getGenerationContext() { return gc; } @@ -545,7 +552,7 @@ * @param hirBlock * The block that is to be registered. */ - protected void registerMapping(int pc, Laziness lazy, OPT_BasicBlock hirBlock) { + protected final void registerMapping(int pc, Laziness lazy, OPT_BasicBlock hirBlock) { blockMap.put(lazy.makeKey(pc), hirBlock); } @@ -559,7 +566,7 @@ * The lazy state assumed within the returned trace. * @return An appropriate basic block or null if no translation exists. */ - protected OPT_BasicBlock findMapping(int pc, Laziness lazy) { + protected final OPT_BasicBlock findMapping(int pc, Laziness lazy) { return blockMap.get(lazy.makeKey(pc)); } @@ -757,13 +764,24 @@ * within the code cache c) The trace is already too long d) the branch is * supposedly a CALL or RETURN */ + + boolean decision = DBT_Options.singleInstrTranslation == false && jump.type == BranchType.DIRECT_BRANCH && !shallTraceStop(); + if (!decision) { + + if (DBT_Options.debugBranchResolution) { + String text = (!decision ? "Not inlining " : "Inlining "); + text += jump.type + " to 0x" + Integer.toHexString(targetPc); + System.out.println(text); + } + + return false; + } + + //only query the code cache if we have to DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); + decision = (compiledTrace == null || compiledTrace.getNumberOfInstructions() < 20) ; - boolean decision = DBT_Options.singleInstrTranslation == false - && (compiledTrace == null || compiledTrace.getNumberOfInstructions() < 20) && !shallTraceStop() - && jump.type != BranchType.CALL && jump.type != BranchType.RETURN; - if (DBT_Options.debugBranchResolution) { String text = (!decision ? "Not inlining " : "Inlining "); text += jump.type + " to 0x" + Integer.toHexString(targetPc); @@ -967,18 +985,6 @@ } /** - * Should a trace follow a branch and link instruction or should it terminate - * the trace? - * - * @param pc - * the address of the branch and link instruction - * @return whether the trace should continue - */ - public boolean traceContinuesAfterBranchAndLink(int pc) { - return shallTraceStop() == false; - } - - /** * Load all the registers from the ProcessSpace into the pre-fill block */ private void preFillAllRegisters() { @@ -1169,6 +1175,7 @@ if (intTemps == null) { intTemps = new OPT_Register[10]; } + OPT_Register result = intTemps[num]; if (result == null) { OPT_RegisterOperand regOp = gc.temps.makeTempInt(); @@ -1459,7 +1466,60 @@ callInstruction.bcIndex = trace.registerDynamicLink(methodRef, callType); appendInstruction(callInstruction); } + + /** + * Execute an inlining decision inlDec for the CALL instruction + * callSite that is contained in ir. + * + * @param inlDec the inlining decision to execute + * @param ir the governing IR + * @param callSite the call site to inline + */ + public void appendInlinedCall(OPT_Instruction callSite) { + + if (DBT.VerifyAssertions) + DBT._assert(Call.conforms(callSite)); + + OPT_BasicBlock next = createBlockAfterCurrent(); + + //Find out where the call site is and isolate it in its own basic block. + currentBlock = createBlockAfterCurrent(); + currentBlock.appendInstruction(callSite); + + OPT_BasicBlock in = currentBlock.prevBasicBlockInCodeOrder(); + OPT_BasicBlock out = currentBlock.nextBasicBlockInCodeOrder(); + + // Clear the sratch object of any register operands being + // passed as parameters. + // BC2IR uses this field for its own purposes, and will be confused + // if the scratch object has been used by someone else and not cleared. + for (int i = 0; i < Call.getNumberOfParams(callSite); i++) { + OPT_Operand arg = Call.getParam(callSite, i); + if (arg instanceof OPT_RegisterOperand) { + ((OPT_RegisterOperand) arg).scratchObject = null; + } + } + // Execute the inlining decision, updating ir.gc's state. + OPT_InlineDecision inlDec = OPT_InlineDecision.YES(Call.getMethod(callSite).getTarget(), ""); + OPT_GenerationContext childgc = OPT_Inliner.execute(inlDec, gc, null, callSite); + + // Splice the callee into the caller's code order + gc.cfg.removeFromCFGAndCodeOrder(currentBlock); + gc.cfg.breakCodeOrder(in, out); + gc.cfg.linkInCodeOrder(in, childgc.cfg.firstInCodeOrder()); + gc.cfg.linkInCodeOrder(childgc.cfg.lastInCodeOrder(), out); + + // Splice the callee into the caller's CFG + in.insertOut(childgc.prologue); + + if (childgc.epilogue != null) { + childgc.epilogue.insertOut(out); + } + + currentBlock = next; + } + /** Report some debug output */ protected abstract void report(String str); @@ -1470,8 +1530,7 @@ * Plant instructions modifying a lazy state into one with no laziness * * @param laziness - * the laziness to modify - */ + * the laziness to modify */ public abstract void resolveLaziness(Laziness laziness); /** @@ -1481,20 +1540,17 @@ * the status of the lazy evaluation * @param pc * the program counter for the instruction - * @return the next instruction address or -1 - */ + * @return the next instruction address or -1 */ protected abstract int translateInstruction(Laziness lazy, int pc); /** * Fill all the registers from the ProcessSpace, that is take the register - * values from the process space and place them in the traces registers. - */ + * values from the process space and place them in the traces registers. */ protected abstract void fillAllRegisters(); /** * Spill all the registers, that is put them from the current running trace - * into the process space - */ + * into the process space. */ protected abstract void spillAllRegisters(); /** Return an array of unused registers */ Modified: src/org/binarytranslator/generic/execution/StagedEmulationController.java =================================================================== --- src/org/binarytranslator/generic/execution/StagedEmulationController.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/generic/execution/StagedEmulationController.java 2007-08-14 15:32:09 UTC (rev 164) @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.TreeMap; import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; @@ -38,7 +39,7 @@ } /** Maps a dynamic basic block to the address of the first instruction within that block. */ - private final HashMap<Integer, DynamicBasicBlock> traceCache = new HashMap<Integer, DynamicBasicBlock>(); + private final TreeMap<Integer, DynamicBasicBlock> traceCache = new TreeMap<Integer, DynamicBasicBlock>(); /** The interpreter that is used to perform the actual execution of single instructions. */ private final Interpreter interpreter; @@ -70,10 +71,13 @@ //No, so stop and create a trace from the decoded instructions DynamicBasicBlock newTrace = new DynamicBasicBlock(instructions); - if (instructions.size() > 3) { +// add this trace to the trace cache + traceCache.put(traceStart, newTrace); + + /*if (instructions.size() > 3) { //add this trace to the trace cache, if it contains enough instructions traceCache.put(traceStart, newTrace); - } + }*/ return newTrace; } @@ -94,6 +98,8 @@ trace.compiledTrace = new DBT_Trace(ps, pc); trace.compiledTrace.compile(); trace.instructions = null; + + ps.codeCache.add(pc, trace.compiledTrace); } /** Modified: src/org/binarytranslator/generic/memory/CallBasedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/CallBasedMemory.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/generic/memory/CallBasedMemory.java 2007-08-14 15:32:09 UTC (rev 164) @@ -99,7 +99,7 @@ /** * A translation helper for generating code */ - protected CodeTranslator helper; + protected CodeTranslator translator; /** * The generation context we're translating within @@ -162,7 +162,7 @@ * page table into a register */ public void initTranslate(CodeTranslator helper) { - this.helper = helper; + this.translator = helper; this.gc = helper.getGenerationContext(); OPT_RegisterOperand memoryOp = helper.makeTemp(memoryType); helper.appendInstruction(GetField.create(GETFIELD, memoryOp, @@ -187,21 +187,27 @@ */ private void translateLoad(VM_Method loadMethod, int bcIndex, OPT_Operand addr, OPT_RegisterOperand dest) { - OPT_Instruction s = Call.create(CALL, dest, null, null, null, 2); + OPT_Instruction s = Call.create(CALL, dest.copyRO(), null, null, null, 2); VM_MethodReference loadMethRef = loadMethod.getMemberRef() .asMethodReference(); - OPT_MethodOperand methOp = OPT_MethodOperand.VIRTUAL(loadMethRef, - loadMethod); + OPT_MethodOperand methOp = OPT_MethodOperand.VIRTUAL(loadMethRef, loadMethod); OPT_RegisterOperand memoryOp = new OPT_RegisterOperand(memory, memoryType); Call.setParam(s, 0, memoryOp); // Sets 'this' pointer - Call.setParam(s, 1, addr); + Call.setParam(s, 1, addr.copy()); Call.setGuard(s, new OPT_TrueGuardOperand()); Call.setMethod(s, methOp); Call.setAddress(s, new OPT_AddressConstantOperand(loadMethod.getOffset())); - s.position = gc.inlineSequence; - s.bcIndex = bcIndex; - helper.appendInstruction(s); + + if (DBT_Options.inlineCallbasedMemory) { + translator.appendInlinedCall(s); + } + else + { + s.position = gc.inlineSequence; + s.bcIndex = bcIndex; + translator.appendInstruction(s); + } } /** @@ -335,14 +341,21 @@ storeMethod); OPT_RegisterOperand memoryOp = new OPT_RegisterOperand(memory, memoryType); Call.setParam(s, 0, memoryOp); // Sets 'this' pointer - Call.setParam(s, 1, addr); - Call.setParam(s, 2, src); + Call.setParam(s, 1, addr.copy()); + Call.setParam(s, 2, src.copy()); Call.setGuard(s, new OPT_TrueGuardOperand()); Call.setMethod(s, methOp); Call.setAddress(s, new OPT_AddressConstantOperand(storeMethod.getOffset())); - s.position = gc.inlineSequence; - s.bcIndex = bcIndex; - helper.appendInstruction(s); + + if (DBT_Options.inlineCallbasedMemory) { + translator.appendInlinedCall(s); + } + else + { + s.position = gc.inlineSequence; + s.bcIndex = bcIndex; + translator.appendInstruction(s); + } } /** Modified: src/org/binarytranslator/generic/memory/IntAddressedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedMemory.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/generic/memory/IntAddressedMemory.java 2007-08-14 15:32:09 UTC (rev 164) @@ -14,6 +14,7 @@ import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.fault.SegmentationFault; import org.jikesrvm.VM_Configuration; +import org.vmmagic.pragma.Inline; /** * IntAddressedMemory: @@ -85,6 +86,7 @@ /** * Return the offset part of the address */ + @Inline protected int getOffset(int address) { return (address & (PAGE_SIZE - 1)) >>> 2; } @@ -92,6 +94,7 @@ /** * Return the page table entry part of the address */ + @Inline private static final int getPTE(int address) { return address >>> OFFSET_BITS; } @@ -311,9 +314,10 @@ MemoryMapException.unalignedAddress(addr); } // Check file offset is page aligned - if ((offset % PAGE_SIZE) != 0) { + /*if ((offset % PAGE_SIZE) != 0) { MemoryMapException.unalignedFileOffset(offset); - } + }*/ + if (DBT_Options.debugRuntime) { System.out.println("Mapping file " + file + " offset=" + offset + " addr=0x" + Integer.toHexString(addr) + " len=" + len Modified: src/org/binarytranslator/generic/memory/IntAddressedPreSwappedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedPreSwappedMemory.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/generic/memory/IntAddressedPreSwappedMemory.java 2007-08-14 15:32:09 UTC (rev 164) @@ -420,29 +420,29 @@ // Extract the memory page number from addr. OPT_RegisterOperand vpnRegOp = new OPT_RegisterOperand(vpnReg, VM_TypeReference.Int); - helper.appendInstruction(Binary.create(INT_USHR, vpnRegOp, + translator.appendInstruction(Binary.create(INT_USHR, vpnRegOp, addr, new OPT_IntConstantOperand(OFFSET_BITS))); // Extract the location of the address within the page. OPT_RegisterOperand offsetRegOp = new OPT_RegisterOperand(offsetReg, VM_TypeReference.Int); - helper.appendInstruction(Binary.create(INT_AND, offsetRegOp, + translator.appendInstruction(Binary.create(INT_AND, offsetRegOp, addr.copyRO(), new OPT_IntConstantOperand(PAGE_SIZE - 1))); - helper.appendInstruction(Binary.create(INT_USHR, offsetRegOp + translator.appendInstruction(Binary.create(INT_USHR, offsetRegOp .copyRO(), offsetRegOp.copyRO(), new OPT_IntConstantOperand(2))); // Retrieve the int[] for the correct page into pageReg. OPT_RegisterOperand pageRegOp = new OPT_RegisterOperand(pageReg, VM_TypeReference.IntArray); - helper.appendInstruction(ALoad.create(REF_ALOAD, pageRegOp, + translator.appendInstruction(ALoad.create(REF_ALOAD, pageRegOp, new OPT_RegisterOperand(readableMemoryReg, VM_TypeReference.ObjectReferenceArray), vpnRegOp.copyRO(), new OPT_LocationOperand(VM_TypeReference.IntArray), new OPT_TrueGuardOperand())); // Copy to reg from the correct array element. - helper.appendInstruction(ALoad.create(INT_ALOAD, dest, + translator.appendInstruction(ALoad.create(INT_ALOAD, dest, pageRegOp.copyRO(), offsetRegOp.copyRO(), new OPT_LocationOperand( VM_TypeReference.Int), new OPT_TrueGuardOperand())); } @@ -461,15 +461,15 @@ // Load as 32-bit then mask out what we need translateAlignedLoad32(addr, dest); // addr = (addr & 0x3) * 8 - helper.appendInstruction(Binary.create(INT_AND, + translator.appendInstruction(Binary.create(INT_AND, addr.copyRO(), addr.copyRO(), new OPT_IntConstantOperand(3))); - helper.appendInstruction(Binary.create(INT_SHL, + translator.appendInstruction(Binary.create(INT_SHL, addr.copyRO(), addr.copyRO(), new OPT_IntConstantOperand(3))); // rD <<= addr - helper.appendInstruction(Binary.create(INT_SHL, + translator.appendInstruction(Binary.create(INT_SHL, dest.copyRO(), dest.copyRO(), addr.copyRO())); // rD >>>= 24 - helper.appendInstruction(Binary.create(INT_USHR, dest + translator.appendInstruction(Binary.create(INT_USHR, dest .copyRO(), dest.copyRO(), new OPT_IntConstantOperand(24))); } @@ -487,17 +487,17 @@ // Load as 32-bit then mask out what we need translateAlignedLoad32(addr, dest); // addr = (3 - (addr & 0x3)) * 8 - helper.appendInstruction(Binary.create(INT_AND, + translator.appendInstruction(Binary.create(INT_AND, addr.copyRO(), addr.copyRO(), new OPT_IntConstantOperand(3))); - helper.appendInstruction(Binary.create(INT_SUB, + translator.appendInstruction(Binary.create(INT_SUB, addr.copyRO(), new OPT_IntConstantOperand(3), addr.copyRO())); - helper.appendInstruction(Binary.create(INT_SHL, + translator.appendInstruction(Binary.create(INT_SHL, addr.copyRO(), addr.copyRO(), new OPT_IntConstantOperand(3))); // rD >>>= addr - helper.appendInstruction(Binary.create(INT_USHR, dest + translator.appendInstruction(Binary.create(INT_USHR, dest .copyRO(), dest.copyRO(), addr.copyRO())); // rD &= 0xff - helper.appendInstruction(Binary.create(INT_AND, + translator.appendInstruction(Binary.create(INT_AND, dest.copyRO(), dest.copyRO(), new OPT_IntConstantOperand(0xff))); } @@ -514,43 +514,43 @@ OPT_RegisterOperand dest) { // The block after this load - NB could still need to plant an update for // this instruction in here - OPT_BasicBlock nextBlock = helper.createBlockAfterCurrent(); + OPT_BasicBlock nextBlock = translator.createBlockAfterCurrent(); // Put call based version for (addr & 3 == 3) in aligned3 - OPT_BasicBlock aligned3 = helper.createBlockAfterCurrent(); + OPT_BasicBlock aligned3 = translator.createBlockAfterCurrent(); // Put all other cases in aligned - OPT_BasicBlock aligned = helper.createBlockAfterCurrent(); + OPT_BasicBlock aligned = translator.createBlockAfterCurrent(); // Compute tempReg = addr & 3 OPT_RegisterOperand tempRegOp = new OPT_RegisterOperand(tempReg, VM_TypeReference.Int); - helper.appendInstruction(Binary.create(INT_AND, tempRegOp, + translator.appendInstruction(Binary.create(INT_AND, tempRegOp, addr.copyRO(), new OPT_IntConstantOperand(0x3))); // Create if (addr & 3) == 3 goto aligned3 - helper.appendInstruction(IfCmp.create(INT_IFCMP, null, + translator.appendInstruction(IfCmp.create(INT_IFCMP, null, tempRegOp.copyRO(), new OPT_IntConstantOperand(0x3), - OPT_ConditionOperand.EQUAL(), aligned3.makeJumpTarget(), helper + OPT_ConditionOperand.EQUAL(), aligned3.makeJumpTarget(), translator .getConditionalBranchProfileOperand(false))); - helper.getCurrentBlock().insertOut(aligned3); + translator.getCurrentBlock().insertOut(aligned3); // Create aligned code - helper.setCurrentBlock(aligned); + translator.setCurrentBlock(aligned); translateAlignedLoad32(addr, dest); // tempReg = (addr & 0x3) * 8 - helper.appendInstruction(Binary.create(INT_SHL, tempRegOp + translator.appendInstruction(Binary.create(INT_SHL, tempRegOp .copyRO(), tempRegOp.copyRO(), new OPT_IntConstantOperand(3))); // rD <<= tempReg - helper.appendInstruction(Binary.create(INT_SHL, + translator.appendInstruction(Binary.create(INT_SHL, dest.copyRO(), dest.copyRO(), tempRegOp.copyRO())); // rD >>= 16 - helper.appendInstruction(Binary.create(INT_SHR, + translator.appendInstruction(Binary.create(INT_SHR, dest.copyRO(), dest.copyRO(), new OPT_IntConstantOperand(16))); - helper.appendInstruction(Goto.create(GOTO, nextBlock + translator.appendInstruction(Goto.create(GOTO, nextBlock .makeJumpTarget())); aligned.deleteNormalOut(); aligned.insertOut(nextBlock); // Create aligned3 code - helper.setCurrentBlock(aligned3); + translator.setCurrentBlock(aligned3); translateCallBasedLoadSigned16(addr.copyRO(), dest.copyRO()); // Move to empty block for rest of load instruction - helper.setCurrentBlock(nextBlock); + translator.setCurrentBlock(nextBlock); } /** @@ -566,45 +566,45 @@ OPT_RegisterOperand dest) { // The block after this load - NB could still need to plant an update for // this instruction in here - OPT_BasicBlock nextBlock = helper.createBlockAfterCurrent(); + OPT_BasicBlock nextBlock = translator.createBlockAfterCurrent(); // Put call based version for (addr & 3 == 3) in aligned3 - OPT_BasicBlock aligned3 = helper.createBlockAfterCurrent(); + OPT_BasicBlock aligned3 = translator.createBlockAfterCurrent(); // Put all other cases in aligned - OPT_BasicBlock aligned = helper.createBlockAfterCurrent(); + OPT_BasicBlock aligned = translator.createBlockAfterCurrent(); // Compute tempReg = addr & 3 OPT_RegisterOperand tempRegOp = new OPT_RegisterOperand(tempReg, VM_TypeReference.Int); - helper.appendInstruction(Binary.create(INT_AND, tempRegOp, + translator.appendInstruction(Binary.create(INT_AND, tempRegOp, addr.copyRO(), new OPT_IntConstantOperand(0x3))); // Create if (addr & 3) == 3 goto aligned3 - helper.appendInstruction(IfCmp.create(INT_IFCMP, null, + translator.appendInstruction(IfCmp.create(INT_IFCMP, null, tempRegOp.copyRO(), new OPT_IntConstantOperand(0x3), - OPT_ConditionOperand.EQUAL(), aligned3.makeJumpTarget(), helper + OPT_ConditionOperand.EQUAL(), aligned3.makeJumpTarget(), translator .getConditionalBranchProfileOperand(false))); - helper.getCurrentBlock().insertOut(aligned3); + translator.getCurrentBlock().insertOut(aligned3); // Create aligned code - helper.setCurrentBlock(aligned); + translator.setCurrentBlock(aligned); translateAlignedLoad32(addr, dest); // tempReg = (2 - (addr & 0x3)) * 8 - helper.appendInstruction(Binary.create(INT_SUB, tempRegOp + translator.appendInstruction(Binary.create(INT_SUB, tempRegOp .copyRO(), new OPT_IntConstantOperand(2), tempRegOp.copyRO())); - helper.appendInstruction(Binary.create(INT_SHL, tempRegOp + translator.appendInstruction(Binary.create(INT_SHL, tempRegOp .copyRO(), tempRegOp.copyRO(), new OPT_IntConstantOperand(3))); // rD >>>= tempReg - helper.appendInstruction(Binary.create(INT_USHR, dest + translator.appendInstruction(Binary.create(INT_USHR, dest .copyRO(), dest.copyRO(), tempRegOp.copyRO())); // rD &= 0xffff - helper.appendInstruction(Binary.create(INT_AND, + translator.appendInstruction(Binary.create(INT_AND, dest.copyRO(), dest.copyRO(), new OPT_IntConstantOperand(0xffff))); - helper.appendInstruction(Goto.create(GOTO, nextBlock + translator.appendInstruction(Goto.create(GOTO, nextBlock .makeJumpTarget())); aligned.deleteNormalOut(); aligned.insertOut(nextBlock); // Create aligned3 code - helper.setCurrentBlock(aligned3); + translator.setCurrentBlock(aligned3); translateCallBasedLoadUnsigned16(addr.copyRO(), dest.copyRO()); // Move to empty block for rest of load instruction - helper.setCurrentBlock(nextBlock); + translator.setCurrentBlock(nextBlock); } /** @@ -618,34 +618,34 @@ public void translateLoad32(OPT_RegisterOperand addr, OPT_RegisterOperand dest) { // The block after this load - NB could still need to plant an update for // this instruction in here - OPT_BasicBlock nextBlock = helper.createBlockAfterCurrent(); + OPT_BasicBlock nextBlock = translator.createBlockAfterCurrent(); // Put call based version for (addr & 3 != 0) in aligned123 - OPT_BasicBlock aligned123 = helper.createBlockAfterCurrent(); + OPT_BasicBlock aligned123 = translator.createBlockAfterCurrent(); // Put case (addr & 3 == 0) in aligned - OPT_BasicBlock aligned = helper.createBlockAfterCurrent(); + OPT_BasicBlock aligned = translator.createBlockAfterCurrent(); // Compute tempReg = addr & 3 OPT_RegisterOperand tempRegOp = new OPT_RegisterOperand(tempReg, VM_TypeReference.Int); - helper.appendInstruction(Binary.create(INT_AND, tempRegOp, + translator.appendInstruction(Binary.create(INT_AND, tempRegOp, addr.copyRO(), new OPT_IntConstantOperand(0x3))); // Create if (addr & 3) == 3 goto aligned3 - helper.appendInstruction(IfCmp.create(INT_IFCMP, null, + translator.appendInstruction(IfCmp.create(INT_IFCMP, null, tempRegOp.copyRO(), new OPT_IntConstantOperand(0), OPT_ConditionOperand - .NOT_EQUAL(), aligned123.makeJumpTarget(), helper + .NOT_EQUAL(), aligned123.makeJumpTarget(), translator .getConditionalBranchProfileOperand(false))); - helper.getCurrentBlock().insertOut(aligned123); + translator.getCurrentBlock().insertOut(aligned123); // Create aligned code - helper.setCurrentBlock(aligned); + translator.setCurrentBlock(aligned); translateAlignedLoad32(addr, dest); - helper.appendInstruction(Goto.create(GOTO, nextBlock + translator.appendInstruction(Goto.create(GOTO, nextBlock .makeJumpTarget())); aligned.deleteNormalOut(); aligned.insertOut(nextBlock); // Create aligned3 code - helper.setCurrentBlock(aligned123); + translator.setCurrentBlock(aligned123); translateCallBasedLoad32(addr.copyRO(), dest.copyRO()); // Move to empty block for rest of load instruction - helper.setCurrentBlock(nextBlock); + translator.setCurrentBlock(nextBlock); } /** @@ -662,29 +662,29 @@ // Extract the memory page number from addr. OPT_RegisterOperand vpnRegOp = new OPT_RegisterOperand(vpnReg, VM_TypeReference.Int); - helper.appendInstruction(Binary.create(INT_USHR, vpnRegOp, + translator.appendInstruction(Binary.create(INT_USHR, vpnRegOp, addr, new OPT_IntConstantOperand(OFFSET_BITS))); // Extract the location of the address within the page. OPT_RegisterOperand offsetRegOp = new OPT_RegisterOperand(offsetReg, VM_TypeReference.Int); - helper.appendInstruction(Binary.create(INT_AND, offsetRegOp, + translator.appendInstruction(Binary.create(INT_AND, offsetRegOp, addr.copyRO(), new OPT_IntConstantOperand(PAGE_SIZE - 1))); - helper.appendInstruction(Binary.create(INT_USHR, offsetRegOp + translator.appendInstruction(Binary.create(INT_USHR, offsetRegOp .copyRO(), offsetRegOp.copyRO(), new OPT_IntConstantOperand(2))); // Retrieve the int[] for the correct page into pageReg. OPT_RegisterOperand pageRegOp = new OPT_RegisterOperand(pageReg, VM_TypeReference.IntArray); - helper.appendInstruction(ALoad.create(REF_ALOAD, pageRegOp, + translator.appendInstruction(ALoad.create(REF_ALOAD, pageRegOp, new OPT_RegisterOperand(writableMemoryReg, VM_TypeReference.ObjectReferenceArray), vpnRegOp.copyRO(), new OPT_LocationOperand(VM_TypeReference.IntArray), new OPT_TrueGuardOperand())); // Copy to reg from the correct array element. - helper.appendInstruction(ALoad.create(INT_ALOAD, dest, + translator.appendInstruction(ALoad.create(INT_ALOAD, dest, pageRegOp.copyRO(), offsetRegOp.copyRO(), new OPT_LocationOperand( VM_TypeReference.Int), new OPT_TrueGuardOperand())); } @@ -703,29 +703,29 @@ // Extract the memory page number from addr. OPT_RegisterOperand vpnRegOp = new OPT_RegisterOperand(vpnReg, VM_TypeReference.Int); - helper.appendInstruction(Binary.create(INT_USHR, vpnRegOp, + translator.appendInstruction(Binary.create(INT_USHR, vpnRegOp, addr, new OPT_IntConstantOperand(OFFSET_BITS))); // Extract the location of the address within the page. OPT_RegisterOperand offsetRegOp = new OPT_RegisterOperand(offsetReg, VM_TypeReference.Int); - helper.appendInstruction(Binary.create(INT_AND, offsetRegOp, + translator.appendInstruction(Binary.create(INT_AND, offsetRegOp, addr.copyRO(), new OPT_IntConstantOperand(PAGE_SIZE - 1))); - helper.appendInstruction(Binary.create(INT_USHR, offsetRegOp + translator.appendInstruction(Binary.create(INT_USHR, offsetRegOp .copyRO(), offsetRegOp.copyRO(), new OPT_IntConstantOperand(2))); // Retrieve the int[] for the correct page into pageReg. OPT_RegisterOperand pageRegOp = new OPT_RegisterOperand(pageReg, VM_TypeReference.IntArray); - helper.appendInstruction(ALoad.create(REF_ALOAD, pageRegOp, + translator.appendInstruction(ALoad.create(REF_ALOAD, pageRegOp, new OPT_RegisterOperand(writableMemoryReg, VM_TypeReference.ObjectReferenceArray), vpnRegOp.copyRO(), new OPT_LocationOperand(VM_TypeReference.IntArray), new OPT_TrueGuardOperand())); // Copy to reg from the correct array element. - helper.appendInstruction(ALoad.create(INT_ASTORE, src, + translator.appendInstruction(ALoad.create(INT_ASTORE, src, pageRegOp.copyRO(), offsetRegOp.copyRO(), new OPT_LocationOperand( VM_TypeReference.Int), new OPT_TrueGuardOperand())); } Modified: src/org/binarytranslator/generic/os/loader/elf/ELF_File.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-08-14 15:32:09 UTC (rev 164) @@ -215,7 +215,7 @@ public static boolean conforms(String filename) { RandomAccessFile rFile = null; - report("Testing is file is ELF: " + filename); + report("Testing if file is ELF: " + filename); try { rFile = new RandomAccessFile(filename, "r"); Modified: src/org/binarytranslator/generic/os/process/ProcessSpace.java =================================================================== --- src/org/binarytranslator/generic/os/process/ProcessSpace.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/generic/os/process/ProcessSpace.java 2007-08-14 15:32:09 UTC (rev 164) @@ -70,8 +70,7 @@ * @param trace * @return a HIR generator */ - public abstract CodeTranslator createTranslator( - OPT_GenerationContext context, DBT_Trace trace) throws UnsupportedOperationException ; + public abstract CodeTranslator createTranslator(OPT_GenerationContext context, DBT_Trace trace) throws UnsupportedOperationException ; /** * Returns an instance of {@link Interpreter} that can be used to interpret instructions Modified: src/org/binarytranslator/vmInterface/DBT_Trace.java =================================================================== --- src/org/binarytranslator/vmInterface/DBT_Trace.java 2007-08-11 11:28:50 UTC (rev 163) +++ src/org/binarytranslator/vmInterface/DBT_Trace.java 2007-08-14 15:32:09 UTC (rev 164) @@ -117,7 +117,7 @@ * This list stores at which bytecode index a specific method call is executed. * The index of an element plus {@link #CUSTOM_CALL_BCINDEX_BASE} equals the bytecode index * for the call.*/ - private List<CustomCallInformation> customCalls = new ArrayList<CustomCallInformation>(); + private final List<CustomCallInformation> customCalls = new ArrayList<CustomCallInformation>(); /** * Create an optimizing compiler HIR code generator for this trace @@ -126,7 +126,9 @@ * the generation context for the HIR generation * @return a HIR generator */ + @Override public OPT_HIRGenerator createHIRGenerator(OPT_GenerationContext context) { + return ps.createTranslator(context, this); } @@ -322,7 +324,7 @@ * Size of bytecodes for this method */ public int getBytecodeLength() { - return 256; + return numberOfInstructions == 0 ? 256 : numberOfInstructions; } public int getNumberOfInstructions() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-11 11:29:13
|
Revision: 163 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=163&view=rev Author: michael_baer Date: 2007-08-11 04:28:50 -0700 (Sat, 11 Aug 2007) Log Message: ----------- - Fixed bugs with Lazy Evaluation - Added option to determine ARM inlining behaviour Modified Paths: -------------- src/org/binarytranslator/DBT.java src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/generic/decoder/CodeTranslator.java Modified: src/org/binarytranslator/DBT.java =================================================================== --- src/org/binarytranslator/DBT.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/DBT.java 2007-08-11 11:28:50 UTC (rev 163) @@ -17,7 +17,7 @@ */ public final class DBT { /** Should the following assertion be checked? */ - public static final boolean VerifyAssertions = true; + public static final boolean VerifyAssertions = VM.VerifyAssertions; /** * Assert the following condition is true, if false then fail with stack trace Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/DBT_Options.java 2007-08-11 11:28:50 UTC (rev 163) @@ -25,7 +25,7 @@ public final static boolean buildForSunVM = false; /** Enable the profiling of application during interpretation? */ - public final static boolean profileDuringInterpretation = true; + public final static boolean profileDuringInterpretation = false; /** Debug binary loading */ public final static boolean debugLoader = true; @@ -182,8 +182,10 @@ private static void parseArmOption(String key, String value) { if (key.equalsIgnoreCase("optimizeByProfiling")) { ARM_Options.optimizeTranslationByProfiling = Boolean.parseBoolean(value); - } else if (key.equalsIgnoreCase("flagBehaviour")) { - ARM_Options.flagBehaviour = ARM_Options.FlagBehaviour.valueOf(value); + } else if (key.equalsIgnoreCase("flagEvaluation")) { + ARM_Options.flagEvaluation = ARM_Options.FlagBehaviour.valueOf(value); + } else if (key.equalsIgnoreCase("inlining")) { + ARM_Options.inlining = ARM_Options.InliningBehaviour.valueOf(value); } else { throw new Error("Unknown ARM option: " + key); Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/Main.java 2007-08-11 11:28:50 UTC (rev 163) @@ -105,7 +105,7 @@ //on SUN's VM, only the interpreter has been tested if (DBT_Options.buildForSunVM) { - DBT_Options.executionController = ExecutionController.Type.StagedEmulation; + DBT_Options.executionController = ExecutionController.Type.Interpreter; } //load a previously saved branch profile from file, if the user requested it Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-11 11:28:50 UTC (rev 163) @@ -9,6 +9,7 @@ import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; +import org.binarytranslator.generic.branchprofile.BranchProfile.BranchType; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.decoder.Laziness; import org.binarytranslator.vmInterface.DBT_Trace; @@ -143,17 +144,17 @@ super(context, trace); translator = new ARM_Translator((ARM_ProcessSpace)ps, this); - switch (ARM_Options.flagBehaviour) { - case ImmediateEvaluation: + switch (ARM_Options.flagEvaluation) { + case Immediate: flagBehavior = new ARM_ImmediateFlagBehavior(); break; - case LazyEvaluation: + case Lazy: flagBehavior = new ARM_LazyFlagBehavior(); break; default: - throw new RuntimeException("Unexpected flag behaviour: " + ARM_Options.flagBehaviour); + throw new RuntimeException("Unexpected flag behaviour: " + ARM_Options.flagEvaluation); } } @@ -409,7 +410,6 @@ @Override public void onFlagRead(Flag flag, ARM_Laziness lazy) { resolveFlag(flag, lazy); - } @Override @@ -463,6 +463,32 @@ return result; } + @Override + protected boolean inlineBranchInstruction(int targetPc, UnresolvedJumpInstruction jump) { + + switch (ARM_Options.inlining) + { + case Default: + return super.inlineBranchInstruction(targetPc, jump); + + case DynamicJumps: + if (jump.type == BranchType.INDIRECT_BRANCH) + return true; + else + return super.inlineBranchInstruction(targetPc, jump); + + case Functions: + if (jump.type == BranchType.CALL || jump.type == BranchType.RETURN) + return true; + else + return super.inlineBranchInstruction(targetPc, jump); + + default: + throw new RuntimeException("Unexpected inlining type."); + } + + } + /** * Returns a RegisterOperand that contains a reference to the currently used ARM_Registers instance. * Use this reference when calling functions on ARM_Registers. @@ -648,18 +674,20 @@ } public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + zeroUsed = negativeUsed = true; flagBehavior.appendLogicalFlags(lazy, result); } public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + zeroUsed = negativeUsed = carryUsed = overflowUsed = true; flagBehavior.appendSubFlags(lazy, result, op1, op2); } public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + zeroUsed = negativeUsed = carryUsed = overflowUsed = true; flagBehavior.appendAddFlags(lazy, result, op1, op2); } - - + @Override protected OPT_Register[] getUnusedRegisters() { Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java 2007-08-11 11:28:50 UTC (rev 163) @@ -1026,7 +1026,7 @@ public LongMultiply(int instr) { super(instr); - unsigned = Utils.getBit(instr, 22); + unsigned = !Utils.getBit(instr, 22); updateConditionCodes = Utils.getBit(instr, 20); accumulate = Utils.getBit(instr, 21); RdHigh = (byte) Utils.getBits(instr, 16, 19); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-08-11 11:28:50 UTC (rev 163) @@ -1375,8 +1375,8 @@ //get rid of the signs, if we're supposed to do unsigned multiplication if (i.unsigned) { - operand1 &= 0xFFFFFFFF; - operand2 &= 0xFFFFFFFF; + operand1 &= (long)0xFFFFFFFFL; + operand2 &= (long)0xFFFFFFFFL; } // calculate the result @@ -1385,7 +1385,7 @@ if (i.accumulate) { //treat the register as an unsigned value long operand = regs.get(i.getRdLow()); - operand &= 0xFFFFFFFF; + operand &= 0xFFFFFFFFL; result += operand; result += regs.get(i.getRdHigh()) << 32; Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-11 11:28:50 UTC (rev 163) @@ -3,10 +3,16 @@ public class ARM_Options { public enum FlagBehaviour { - LazyEvaluation, - ImmediateEvaluation + Lazy, + Immediate } + public enum InliningBehaviour { + Default, + Functions, + DynamicJumps + } + /** Set to true to enable a fastpath for the decoding of data processing instructions.. */ public final static boolean DATAPROCESSING_DECODER_FASTPATH = false; @@ -14,5 +20,7 @@ public static boolean optimizeTranslationByProfiling = false; /** This variable describes, if the translated program shall be optimized using lazy evaluation.*/ - public static FlagBehaviour flagBehaviour = FlagBehaviour.LazyEvaluation; + public static FlagBehaviour flagEvaluation = FlagBehaviour.Lazy; + + public static InliningBehaviour inlining = InliningBehaviour.Default; } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-11 11:28:50 UTC (rev 163) @@ -92,6 +92,9 @@ else instr = ARM_InstructionDecoder.ARM32.decode(instruction, translatorFactory); + if (DBT_Options.debugTranslation) + System.out.println("Translating instruction: " + ARM_Disassembler.disassemble(pc, ps).asString() + " at 0x" + Integer.toHexString(pc)); + if (instr.getCondition() != Condition.AL) { instr = new ConditionalDecorator(instr); } @@ -1327,24 +1330,27 @@ public void translate() { OPT_Operand operand1 = resolveOperand1(); - OPT_Operand operand2 = resolveOperand2(); + OPT_Operand originalOperand2 = resolveOperand2(); OPT_RegisterOperand result = getResultRegister(); OPT_BasicBlock addWithoutCarry = arm2ir.createBlockAfterCurrent(); OPT_BasicBlock addWithCarry = arm2ir.createBlockAfterCurrentNotInCFG(); + + OPT_RegisterOperand operand2 = arm2ir.getTempInt(0); + arm2ir.appendInstruction(Move.create(INT_MOVE, operand2, originalOperand2)); //Is the carry set at all? if not, just jump to addWithoutCarry - arm2ir.appendInstruction(Binary.create(INT_ADD, result, operand1, operand2)); arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.readCarryFlag(lazy), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), addWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(addWithCarry); //Yes, the carry flag is set. Pre-increase the result by one to account for the carry. arm2ir.setCurrentBlock(addWithCarry); - arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), result.copy(), new OPT_IntConstantOperand(1))); + arm2ir.appendInstruction(Binary.create(INT_ADD, operand2.copyRO(), operand2.copy(), new OPT_IntConstantOperand(1))); addWithCarry.insertOut(addWithoutCarry); //Finally, add the second operands to the result arm2ir.setCurrentBlock(addWithoutCarry); + arm2ir.appendInstruction(Binary.create(INT_ADD, result, operand1, operand2.copy())); setAddResult(result, operand1, operand2); } } @@ -1358,24 +1364,27 @@ public void translate() { OPT_Operand operand1 = resolveOperand1(); - OPT_Operand operand2 = resolveOperand2(); + OPT_Operand originalOperand2 = resolveOperand2(); OPT_RegisterOperand result = getResultRegister(); OPT_BasicBlock subWithoutCarry = arm2ir.createBlockAfterCurrent(); OPT_BasicBlock subWithCarry = arm2ir.createBlockAfterCurrentNotInCFG(); + + OPT_RegisterOperand operand2 = arm2ir.getTempInt(0); + arm2ir.appendInstruction(Move.create(INT_MOVE, operand2, originalOperand2)); //Is the carry set? if yes, just jump to subWithoutCarry - arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2)); arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.readCarryFlag(lazy), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), subWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(subWithCarry); //No, the carry flag is not set. That means, we have to use the carry within the subtraction (weird arm logic). arm2ir.setCurrentBlock(subWithCarry); - arm2ir.appendInstruction(Binary.create(INT_SUB, result.copyRO(), result.copy(), new OPT_IntConstantOperand(1))); + arm2ir.appendInstruction(Binary.create(INT_ADD, operand2.copyRO(), operand2.copy(), new OPT_IntConstantOperand(1))); subWithCarry.insertOut(subWithoutCarry); //Finally, subtract the second operands from the result arm2ir.setCurrentBlock(subWithoutCarry); + arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2.copy())); setSubResult(result, operand1, operand2); } } @@ -1846,7 +1855,7 @@ } public int getSuccessor(int pc) { - if (i.offset.getType() == OperandWrapper.Type.Immediate) + if (i.offset.getType() == OperandWrapper.Type.Immediate && !i.link) return readPC() + i.getOffset().getImmediate(); else return -1; @@ -1993,8 +2002,8 @@ if (i.unsigned) { //treat the original ints as unsigned, so get rid of the signs for the longs - arm2ir.appendInstruction(Binary.create(LONG_AND, operand1.copyRO(), operand1.copy(), new OPT_LongConstantOperand(0xFFFFFFFF))); - arm2ir.appendInstruction(Binary.create(LONG_AND, operand2.copyRO(), operand2.copy(), new OPT_LongConstantOperand(0xFFFFFFFF))); + arm2ir.appendInstruction(Binary.create(LONG_AND, operand1.copyRO(), operand1.copy(), new OPT_LongConstantOperand(0xFFFFFFFFL))); + arm2ir.appendInstruction(Binary.create(LONG_AND, operand2.copyRO(), operand2.copy(), new OPT_LongConstantOperand(0xFFFFFFFFL))); } //multiply the two operands @@ -2005,7 +2014,7 @@ OPT_Operand operand3 = arm2ir.getRegister(i.getRdLow()); OPT_RegisterOperand tmp = arm2ir.getTempLong(0); arm2ir.appendInstruction(Unary.create(INT_2LONG, tmp, operand3)); - arm2ir.appendInstruction(Binary.create(LONG_AND, tmp.copyRO(), tmp.copy(), new OPT_LongConstantOperand(0xFFFFFFFF))); + arm2ir.appendInstruction(Binary.create(LONG_AND, tmp.copyRO(), tmp.copy(), new OPT_LongConstantOperand(0xFFFFFFFFL))); arm2ir.appendInstruction(Binary.create(LONG_ADD, result.copyRO(), result.copy(), tmp.copy())); operand3 = arm2ir.getRegister(i.getRdHigh()); @@ -2013,6 +2022,10 @@ arm2ir.appendInstruction(Binary.create(LONG_SHL, tmp.copyRO(), tmp.copy(), new OPT_IntConstantOperand(32))); arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), result.copy(), operand3.copy())); } + + arm2ir.appendInstruction(Unary.create(LONG_2INT, arm2ir.getRegister(i.getRdLow()) ,result.copy())); + arm2ir.appendInstruction(Binary.create(LONG_SHR, result.copyRO(), result.copy(), new OPT_IntConstantOperand(32))); + arm2ir.appendInstruction(Unary.create(LONG_2INT, arm2ir.getRegister(i.getRdHigh()) ,result.copy())); if (i.updateConditionCodes) { //set the negative flag @@ -2054,10 +2067,10 @@ //do we have to transfer the saved or the current PSR? if (i.transferSavedPSR) { - call = createCallToRegisters("getSPSR", "()V", 0); + call = createCallToRegisters("getSPSR", "()I", 0); } else { - call = createCallToRegisters("getCPSR", "()V", 0); + call = createCallToRegisters("getCPSR", "()I", 0); } Call.setResult(call, psrValue); Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-11 11:28:50 UTC (rev 163) @@ -165,7 +165,7 @@ /** This class stores information about a jump instruction within the current trace, whose * target has not yet been resolved. */ - private final static class UnresolvedJumpInstruction { + protected final static class UnresolvedJumpInstruction { /** A reference to the jump instruction within the code. This is either a GOTO or SWITCH instruction. */ public final OPT_Instruction instruction; @@ -306,6 +306,10 @@ // Move currentBlock along currentBlock = nextBlock; } else { + + if (DBT_Options.debugTranslation) + System.out.println("Translating subtrace for 0x" + Integer.toHexString(pc)); + do { if (DBT.VerifyAssertions) DBT._assert(currentBlock.getNumberOfRealInstructions() == 0); @@ -351,6 +355,9 @@ break; } } while (pc != -1); + + if (DBT_Options.debugTranslation) + System.out.println("Done translating subtrace."); } } @@ -608,7 +615,7 @@ // serves more as a placeholder and might be mutated later on. appendInstruction(branch); UnresolvedJumpInstruction unresolvedJump = new UnresolvedJumpInstruction( - branch, (Laziness) targetLaziness.clone(), currentPC, targetPC, BranchType.CALL); + branch, (Laziness) targetLaziness.clone(), currentPC, targetPC, branchType); unresolvedDirectBranches.add(unresolvedJump); switch (branchType) { @@ -753,9 +760,17 @@ DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); - return DBT_Options.singleInstrTranslation == false - && (compiledTrace == null || compiledTrace.getNumberOfInstructions() > 30) && !shallTraceStop() + boolean decision = DBT_Options.singleInstrTranslation == false + && (compiledTrace == null || compiledTrace.getNumberOfInstructions() < 20) && !shallTraceStop() && jump.type != BranchType.CALL && jump.type != BranchType.RETURN; + + if (DBT_Options.debugBranchResolution) { + String text = (!decision ? "Not inlining " : "Inlining "); + text += jump.type + " to 0x" + Integer.toHexString(targetPc); + System.out.println(text); + } + + return decision; } /** @@ -782,21 +797,19 @@ // precompiled target if (targetBB != null) return targetBB; - + + if (currentBlock.getNumberOfRealInstructions() != 0) { + currentBlock = createBlockAfterCurrentNotInCFG(); + } + if (!inlineBranchInstruction(targetPc, jump)) { - // Just exit the trace and continue at the target address in a new trace - if (currentBlock.getNumberOfRealInstructions() != 0) { - currentBlock = createBlockAfterCurrentNotInCFG(); - - if (DBT_Options.debugBranchResolution) - System.out.println("Resolving branch to next block."); - } - + //Just exit the trace and continue at the target address in a new trace targetBB = currentBlock; appendTraceExit(jump.lazyStateAtJump, new OPT_IntConstantOperand(targetPc)); registerMapping(targetPc, jump.lazyStateAtJump, targetBB); - } else { + } + else { // Otherwise we will translate the jump into the trace translateSubTrace((Laziness) jump.lazyStateAtJump.clone(), targetPc); targetBB = findMapping(targetPc, jump.lazyStateAtJump); @@ -1299,7 +1312,9 @@ */ public void appendInterpretedInstruction(int pc, Laziness lazy) { - resolveLaziness(lazy); + appendThrowBadInstruction(lazy, pc); + +/* resolveLaziness(lazy); spillAllRegisters(); // Prepare a local variable of type Interpreter @@ -1313,7 +1328,7 @@ VM_MethodReference getInterpreterMethodRef = (VM_MethodReference) VM_MemberReference .findOrCreate(psTref, VM_Atom .findOrCreateAsciiAtom("createInstructionInterpreter"), VM_Atom - .findOrCreateAsciiAtom("()A")); + .findOrCreateAsciiAtom("()Lorg.binarytranslator.generic.decoder.Interpreter;")); VM_Method getInterpreterMethod = getInterpreterMethodRef .resolveInterfaceMethod(); @@ -1345,7 +1360,7 @@ VM_MethodReference decodeMethodRef = (VM_MethodReference) VM_MemberReference .findOrCreate(interpreterTypeRef, VM_Atom .findOrCreateAsciiAtom("decode"), VM_Atom - .findOrCreateAsciiAtom("(I)A")); + .findOrCreateAsciiAtom("(I)Lorg.binarytranslator.generic.decoder.Interpreter.Instruction;")); VM_Method decodeMethod = decodeMethodRef.resolveInterfaceMethod(); methOp = OPT_MethodOperand.INTERFACE(decodeMethodRef, decodeMethod); @@ -1385,7 +1400,7 @@ appendCustomCall(s); // Fill all registers again following interpreted instruction - fillAllRegisters(); + fillAllRegisters();*/ } /** Get the method */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-08 10:22:43
|
Revision: 162 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=162&view=rev Author: michael_baer Date: 2007-08-08 03:22:45 -0700 (Wed, 08 Aug 2007) Log Message: ----------- - Compress flag state into a single integer in ARM_Laziness - Setting blocks as infrequent using profiling information - Move some platform-specific command line options to DBT_Options Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/generic/decoder/CodeTranslator.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/DBT_Options.java 2007-08-08 10:22:45 UTC (rev 162) @@ -13,6 +13,7 @@ import java.util.Map; import java.util.Map.Entry; +import org.binarytranslator.arch.arm.decoder.ARM_Options; import org.binarytranslator.generic.execution.ExecutionController; /** @@ -93,12 +94,6 @@ /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ public static int minTraceValue = 20; - /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using profiling information. */ - public static boolean optimizeTranslationByProfiling = false; - - /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using lazy evaluation.*/ - public static boolean optimizeTranslationByLazyEvaluation = true; - /** Print debug information during the translation of instructions. */ public static boolean debugTranslation = true; @@ -122,7 +117,7 @@ /** Stores the arguments given to the DBT by the user. These are NOT the arguments given to the executable. */ private static HashMap<String, String> dbtArguments = null; - + /** Read and parse the command line arguments. */ public static void parseArguments(String[] args) { @@ -150,7 +145,7 @@ String value = argument.getValue(); try { - parseSingleArgument(arg, value); + parseSingleOption(arg, value); } catch (NumberFormatException e) { throw new Error("Argument " + arg + " is not a valid integer."); @@ -162,14 +157,40 @@ } /** Parses a single argument into the options class. */ - private static void parseSingleArgument(String key, String value) { + private static void parseSingleOption(String key, String value) { - if (!key.startsWith("-X:dbt:")) { - throw new Error("Invalid argument. Argument prefix '-X:dbt:' expected."); + if (!key.startsWith("-X:")) { + throw new Error("Invalid argument. Argument prefix '-X:' expected."); } - key = key.substring(7); + key = key.substring(3); + + if (key.startsWith("dbt:")) { + key = key.substring(4); + + parseDbtOption(key, value); + } + else if (key.startsWith("arm:")) { + key = key.substring(4); + parseArmOption(key, value); + } + else { + throw new Error("Unknown argument."); + } + } + + private static void parseArmOption(String key, String value) { + if (key.equalsIgnoreCase("optimizeByProfiling")) { + ARM_Options.optimizeTranslationByProfiling = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("flagBehaviour")) { + ARM_Options.flagBehaviour = ARM_Options.FlagBehaviour.valueOf(value); + } + else { + throw new Error("Unknown ARM option: " + key); + } + } + private static void parseDbtOption(String key, String value) { if (key.equalsIgnoreCase("debugInstr")) { debugInstr = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("debugRuntime")) { @@ -206,12 +227,7 @@ saveProfileToFile = value; } else if (key.equalsIgnoreCase("minTraceValue")) { minTraceValue = Integer.parseInt(value); - } else if (key.equalsIgnoreCase("optimizeByProfiling")) { - optimizeTranslationByProfiling = Boolean.parseBoolean(value); - } else if (key.equalsIgnoreCase("optimizeByLazy")) { - optimizeTranslationByLazyEvaluation = Boolean.parseBoolean(value); } - else { throw new Error("Unknown DBT option: " + key); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-08 10:22:45 UTC (rev 162) @@ -143,10 +143,18 @@ super(context, trace); translator = new ARM_Translator((ARM_ProcessSpace)ps, this); - if (DBT_Options.optimizeTranslationByLazyEvaluation) + switch (ARM_Options.flagBehaviour) { + case ImmediateEvaluation: + flagBehavior = new ARM_ImmediateFlagBehavior(); + break; + + case LazyEvaluation: flagBehavior = new ARM_LazyFlagBehavior(); - else - flagBehavior = new ARM_ImmediateFlagBehavior(); + break; + + default: + throw new RuntimeException("Unexpected flag behaviour: " + ARM_Options.flagBehaviour); + } } /** ARM has an interchangeable flag behavior. Flags can either be evaluated immediately or on demand using Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java 2007-08-08 10:22:45 UTC (rev 162) @@ -13,7 +13,7 @@ } /** The state of the different ARM flags, compressed as bit fields within an integer. */ - private int flagValid; + private int validFlags; /** The operation that has to be performed to evaluate the remaining registers */ private Operation lazinessOperation; @@ -36,7 +36,7 @@ ARM_LazinessKey(int pc, ARM_Laziness lazy) { this.pc = pc; - int tmpFlagState = lazy.flagValid & 0xF; + int tmpFlagState = lazy.validFlags & 0xF; tmpFlagState |= (lazinessOperation.ordinal() + 1) << 4; this.flagState = (byte)tmpFlagState; @@ -48,7 +48,7 @@ } public ARM_Laziness() { - flagValid = 0xF; //all flags are valid + validFlags = 0xF; //all flags are valid lazinessOperation = Operation.Add; } @@ -57,22 +57,15 @@ } public void setValid(Flag flag, boolean valid) { - flagValid |= 1 << flag.ordinal(); + if (valid) + validFlags |= 1 << flag.ordinal(); + else + validFlags &= ~(1 << flag.ordinal()); } public boolean isValid(Flag flag) { - return (flagValid & (1 << flag.ordinal())) != 0; + return (validFlags & (1 << flag.ordinal())) != 0; } - - public void setAddOperation() { - flagValid = 0; // all flags are invalid - lazinessOperation = Operation.Add; - } - - public void setSubOperation() { - flagValid = 0; // all flags are invalid - lazinessOperation = Operation.Sub; - } public Operation getOperation() { return lazinessOperation; @@ -83,7 +76,7 @@ } public void set(ARM_Laziness other) { - flagValid = other.flagValid; + validFlags = other.validFlags; lazinessOperation = other.lazinessOperation; } @@ -98,7 +91,7 @@ return false; ARM_Laziness other = (ARM_Laziness)o; - return flagValid == other.flagValid && lazinessOperation == other.lazinessOperation; + return validFlags == other.validFlags && lazinessOperation == other.lazinessOperation; } @Override Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-08 10:22:45 UTC (rev 162) @@ -1,5 +1,18 @@ package org.binarytranslator.arch.arm.decoder; public class ARM_Options { + + public enum FlagBehaviour { + LazyEvaluation, + ImmediateEvaluation + } + + /** Set to true to enable a fastpath for the decoding of data processing instructions.. */ public final static boolean DATAPROCESSING_DECODER_FASTPATH = false; + + /** This variable describes, if the translated program shall be optimized using profiling information. */ + public static boolean optimizeTranslationByProfiling = false; + + /** This variable describes, if the translated program shall be optimized using lazy evaluation.*/ + public static FlagBehaviour flagBehaviour = FlagBehaviour.LazyEvaluation; } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-08 10:22:45 UTC (rev 162) @@ -761,7 +761,7 @@ */ private float getSkipProbability() { - if (DBT_Options.optimizeTranslationByProfiling) + if (ARM_Options.optimizeTranslationByProfiling) return -1f; return ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); @@ -922,7 +922,7 @@ conditionalInstruction.translate(); int followingInstructionAddress = pc + (inThumb() ? 2 : 4); - + //yes it did, so we may need to translate the successor instruction twice if (assumeInstructionWillBeSkipped()) { @@ -935,16 +935,27 @@ lazy.set(lazinessWhenInstructionSkipped); } + condInstructionBlock.setInfrequent(); + nextInstruction_InstructionNotSkipped.setInfrequent(); arm2ir.setNextBlock(nextInstruction_InstructionSkipped); - } else { - //Modify block 4 so that it resolves the different laziness correctly - arm2ir.setCurrentBlock(nextInstruction_InstructionSkipped); - nextInstruction_InstructionSkipped.deleteNormalOut(); - arm2ir.appendBranch(followingInstructionAddress, lazinessWhenInstructionSkipped); - - arm2ir.setNextBlock(nextInstruction_InstructionNotSkipped); + if (lazy.equivalent(lazinessWhenInstructionSkipped) && conditionalInstruction.getSuccessor(pc) == followingInstructionAddress) { + //the conditional instruction does not change the lazy state, nor does it change the program flow + //therefore, we block 3 and block 4 always execute the same code. We might as well continue with block 4 then. + arm2ir.setNextBlock(nextInstruction_InstructionSkipped); + } + else { + //we can assume that the instruction will rarely be skipped + nextInstruction_InstructionSkipped.setInfrequent(); + + //Modify block 4 so that it resolves the code the be executed if the instruction was skipped + arm2ir.setCurrentBlock(nextInstruction_InstructionSkipped); + nextInstruction_InstructionSkipped.deleteNormalOut(); + arm2ir.appendBranch(followingInstructionAddress, lazinessWhenInstructionSkipped); + + arm2ir.setNextBlock(nextInstruction_InstructionNotSkipped); + } } } Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-08 10:22:45 UTC (rev 162) @@ -754,7 +754,7 @@ DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); return DBT_Options.singleInstrTranslation == false - && (compiledTrace == null || compiledTrace.getNumberOfInstructions() > 20) && !shallTraceStop() + && (compiledTrace == null || compiledTrace.getNumberOfInstructions() > 30) && !shallTraceStop() && jump.type != BranchType.CALL && jump.type != BranchType.RETURN; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-07 22:28:52
|
Revision: 161 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=161&view=rev Author: michael_baer Date: 2007-08-07 15:28:53 -0700 (Tue, 07 Aug 2007) Log Message: ----------- - Added support for interchangeable flag behaviour and flag laziness on ARM - Improved usage of profiling data for conditional instructions on ARM Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/generic/decoder/CodeTranslator.java src/org/binarytranslator/vmInterface/DBT_Trace.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/DBT_Options.java 2007-08-07 22:28:53 UTC (rev 161) @@ -93,9 +93,12 @@ /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ public static int minTraceValue = 20; - /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using profiling information.. */ + /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using profiling information. */ public static boolean optimizeTranslationByProfiling = false; + /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using lazy evaluation.*/ + public static boolean optimizeTranslationByLazyEvaluation = true; + /** Print debug information during the translation of instructions. */ public static boolean debugTranslation = true; @@ -179,6 +182,8 @@ debugSyscall = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("debugSyscallMore")) { debugSyscallMore = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("debugTranslation")) { + debugTranslation = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("instrOpt0")) { instrOpt0 = Integer.parseInt(value); } else if (key.equalsIgnoreCase("instrOpt1")) { @@ -201,9 +206,12 @@ saveProfileToFile = value; } else if (key.equalsIgnoreCase("minTraceValue")) { minTraceValue = Integer.parseInt(value); - } else if (key.equalsIgnoreCase("optimizeTranslation")) { + } else if (key.equalsIgnoreCase("optimizeByProfiling")) { optimizeTranslationByProfiling = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("optimizeByLazy")) { + optimizeTranslationByLazyEvaluation = Boolean.parseBoolean(value); } + else { throw new Error("Unknown DBT option: " + key); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-07 22:28:53 UTC (rev 161) @@ -3,6 +3,9 @@ import java.util.ArrayList; import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.arch.arm.decoder.ARM_Laziness.Flag; +import org.binarytranslator.arch.arm.decoder.ARM_Laziness.Operation; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; @@ -77,6 +80,9 @@ /** The class performing the actual translation of the bytecode. */ private final ARM_Translator translator; + /** Determines how flags are resolved and if laziness is used.*/ + private final ARM_FlagBehavior flagBehavior; + static { psTref = VM_TypeReference.findOrCreate(ARM_ProcessSpace.class); @@ -136,8 +142,274 @@ public ARM2IR(OPT_GenerationContext context, DBT_Trace trace) { super(context, trace); translator = new ARM_Translator((ARM_ProcessSpace)ps, this); + + if (DBT_Options.optimizeTranslationByLazyEvaluation) + flagBehavior = new ARM_LazyFlagBehavior(); + else + flagBehavior = new ARM_ImmediateFlagBehavior(); } + + /** ARM has an interchangeable flag behavior. Flags can either be evaluated immediately or on demand using + * lazy evaluation. This interface encapsulates the differences. */ + public abstract class ARM_FlagBehavior { + + /** + * Interface helper function. If a flag behaviour wants to set a value of a flag, it shall set + * the {@link OPT_RegisterOperand} returned by this function. + */ + protected final OPT_RegisterOperand getFlag(Flag flag) { + switch (flag) { + case Zero: + return new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); + + case Carry: + return new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); + + case Negative: + return new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); + + case Overflow: + return new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); + + default: + throw new RuntimeException("Unexpected flag type: " + flag); + } + } + /** Called before a flag is written to directly. */ + public abstract void onFlagWrite(Flag flag, ARM_Laziness lazy); + + /** Called before a flag is read. */ + public abstract void onFlagRead(Flag flag, ARM_Laziness lazy); + + /** Called when the ARM flags shall be set by a logical operation. This sets the zero and negative flag. */ + public abstract void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result); + + /** Called when the ARM flags shall be set by a ADD operation. This sets all ARM flags. */ + public abstract void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2); + + /** Called when the ARM flags shall be set by a SUB operation. This sets all ARM flags. */ + public abstract void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2); + } + + /** Implements a flag behavior that will immediately evaluate all flag values. */ + public final class ARM_ImmediateFlagBehavior extends ARM_FlagBehavior { + @Override + public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), result.copy(), op1.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + } + + @Override + public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + + } + + @Override + public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + } + + @Override + public void onFlagRead(Flag flag, ARM_Laziness lazy) { + //nothing to do here, because the flags are already resolved + } + + @Override + public void onFlagWrite(Flag flag, ARM_Laziness lazy) { + //nothing to do here, because the flags are already resolved + } + } + + /** Implements a flag behavior that will use lazy evaluation to only determine a flag value + * when it is necessary. */ + public final class ARM_LazyFlagBehavior extends ARM_FlagBehavior { + + /** Operands for lazy evaluation of condition codes. */ + private OPT_Register lazyOperand1; + private OPT_Register lazyOperand2; + private OPT_Register lazyLogicalOperand; + + public ARM_LazyFlagBehavior() { + //prepare the laziness registers + lazyOperand1 = makeTemp(VM_TypeReference.Int).register; + lazyOperand2 = makeTemp(VM_TypeReference.Int).register; + lazyLogicalOperand = makeTemp(VM_TypeReference.Int).register; + } + + @Override + public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand1, VM_TypeReference.Int), op1.copy())); + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand2, VM_TypeReference.Int), op2.copy())); + + lazy.setValid(Flag.Zero, false); + lazy.setValid(Flag.Negative, false); + lazy.setValid(Flag.Carry, false); + lazy.setValid(Flag.Overflow, false); + lazy.setOperation(Operation.Add); + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + @Override + public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyLogicalOperand, VM_TypeReference.Int), result.copy())); + + lazy.setValid(Flag.Zero, false); + lazy.setValid(Flag.Negative, false); + + switch (lazy.getOperation()) { + case Add: + lazy.setOperation(Operation.LogicalOpAfterAdd); + break; + + case Sub: + lazy.setOperation(Operation.LogicalOpAfterSub); + break; + + case LogicalOpAfterAdd: + case LogicalOpAfterSub: + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + @Override + public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand1, VM_TypeReference.Int), op1.copy())); + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand2, VM_TypeReference.Int), op2.copy())); + + lazy.setValid(Flag.Zero, false); + lazy.setValid(Flag.Negative, false); + lazy.setValid(Flag.Carry, false); + lazy.setValid(Flag.Overflow, false); + lazy.setOperation(Operation.Sub); + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + private void resolveFlag(ARM_Laziness.Flag flag, ARM_Laziness lazy) { + + if (lazy.isValid(flag)) + return; + + if (DBT_Options.debugTranslation) { + System.out.println("Resolving " + flag + " flag."); + } + + OPT_RegisterOperand flagRegister = getFlag(flag); + OPT_RegisterOperand op1 = new OPT_RegisterOperand(lazyOperand1, VM_TypeReference.Int); + OPT_RegisterOperand op2 = new OPT_RegisterOperand(lazyOperand2, VM_TypeReference.Int); + OPT_RegisterOperand result; + + switch (lazy.getOperation()) { + case Add: + result = gc.temps.makeTempInt(); + appendInstruction(Binary.create(INT_ADD, result, op1, op2)); + break; + + case Sub: + result = gc.temps.makeTempInt(); + appendInstruction(Binary.create(INT_SUB, result, op1, op2)); + break; + + case LogicalOpAfterAdd: + case LogicalOpAfterSub: + result = new OPT_RegisterOperand(lazyLogicalOperand, VM_TypeReference.Int); + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + + switch (flag) { + case Zero: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + break; + + case Carry: + switch (lazy.getOperation()) { + case LogicalOpAfterAdd: + case Add: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, result.copy(), op1.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); + break; + + case LogicalOpAfterSub: + case Sub: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + break; + + case Negative: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + break; + + case Overflow: + switch (lazy.getOperation()) { + case Add: + case LogicalOpAfterAdd: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + break; + + case Sub: + case LogicalOpAfterSub: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + + break; + + default: + throw new RuntimeException("Unhandled flag type: " + flag); + } + + lazy.setValid(flag, true); + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + @Override + public void onFlagRead(Flag flag, ARM_Laziness lazy) { + resolveFlag(flag, lazy); + + } + + @Override + public void onFlagWrite(Flag flag, ARM_Laziness lazy) { + lazy.setValid(flag, true); + } + } + @Override protected Laziness createInitialLaziness() { return new ARM_Laziness(); @@ -319,26 +591,67 @@ return new OPT_RegisterOperand(regMap[r], VM_TypeReference.Int); } - public OPT_RegisterOperand getCarryFlag() { + public OPT_Operand readCarryFlag(ARM_Laziness lazy) { carryUsed = true; + flagBehavior.onFlagRead(Flag.Carry, lazy); return new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); } - public OPT_RegisterOperand getZeroFlag() { + public OPT_Operand readZeroFlag(ARM_Laziness lazy) { zeroUsed = true; + flagBehavior.onFlagRead(Flag.Zero, lazy); return new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); } - public OPT_RegisterOperand getNegativeFlag() { + public OPT_Operand readNegativeFlag(ARM_Laziness lazy) { negativeUsed = true; + flagBehavior.onFlagRead(Flag.Negative, lazy); return new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); } - public OPT_RegisterOperand getOverflowFlag() { + public OPT_Operand readOverflowFlag(ARM_Laziness lazy) { overflowUsed = true; + flagBehavior.onFlagRead(Flag.Overflow, lazy); return new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); } + public OPT_RegisterOperand writeCarryFlag(ARM_Laziness lazy) { + carryUsed = true; + flagBehavior.onFlagWrite(Flag.Carry, lazy); + return new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); + } + + public OPT_RegisterOperand writeZeroFlag(ARM_Laziness lazy) { + zeroUsed = true; + flagBehavior.onFlagWrite(Flag.Zero, lazy); + return new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); + } + + public OPT_RegisterOperand writeNegativeFlag(ARM_Laziness lazy) { + negativeUsed = true; + flagBehavior.onFlagWrite(Flag.Negative, lazy); + return new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); + } + + public OPT_RegisterOperand writeOverflowFlag(ARM_Laziness lazy) { + overflowUsed = true; + flagBehavior.onFlagWrite(Flag.Overflow, lazy); + return new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); + } + + public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + flagBehavior.appendLogicalFlags(lazy, result); + } + + public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + flagBehavior.appendSubFlags(lazy, result, op1, op2); + } + + public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + flagBehavior.appendAddFlags(lazy, result, op1, op2); + } + + @Override protected OPT_Register[] getUnusedRegisters() { @@ -372,7 +685,19 @@ @Override public void resolveLaziness(Laziness laziness) { - //NO-OP, as we're not using laziness at the moment + ARM_Laziness lazy = (ARM_Laziness)laziness; + + if (carryUsed) + flagBehavior.onFlagRead(Flag.Carry, lazy); + + if (negativeUsed) + flagBehavior.onFlagRead(Flag.Negative, lazy); + + if (overflowUsed) + flagBehavior.onFlagRead(Flag.Overflow, lazy); + + if (zeroUsed) + flagBehavior.onFlagRead(Flag.Zero, lazy); } @Override Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-08-07 22:28:53 UTC (rev 161) @@ -46,13 +46,18 @@ Instruction decodedInstruction; - if ((address & 0x1) == 1) { - short binaryInstruction = (short)ps.memory.loadInstruction16(address & 0xFFFFFFFE); - decodedInstruction = ARM_InstructionDecoder.Thumb.decode(binaryInstruction); + try { + if ((address & 0x1) == 1) { + short binaryInstruction = (short)ps.memory.loadInstruction16(address & 0xFFFFFFFE); + decodedInstruction = ARM_InstructionDecoder.Thumb.decode(binaryInstruction); + } + else { + int binaryInstruction = ps.memory.loadInstruction32(address); + decodedInstruction = ARM_InstructionDecoder.ARM32.decode(binaryInstruction); + } } - else { - int binaryInstruction = ps.memory.loadInstruction32(address); - decodedInstruction = ARM_InstructionDecoder.ARM32.decode(binaryInstruction); + catch (Exception e) { + return new ARM_DisassembledInstruction("Exception (" + e + ") while reading instruction at 0x" + Integer.toHexString(address)); } DisassemblingVisitor disassembler = new DisassemblingVisitor(); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java 2007-08-07 22:28:53 UTC (rev 161) @@ -2,41 +2,115 @@ import org.binarytranslator.generic.decoder.Laziness; -public class ARM_Laziness extends Laziness { +public final class ARM_Laziness extends Laziness { + public enum Operation { + Add, Sub, LogicalOpAfterAdd, LogicalOpAfterSub + } + + public enum Flag { + Carry, Zero, Negative, Overflow + } + + /** The state of the different ARM flags, compressed as bit fields within an integer. */ + private int flagValid; + + /** The operation that has to be performed to evaluate the remaining registers */ + private Operation lazinessOperation; + final class ARM_LazinessKey extends Key { private final int pc; + private final byte flagState; public int hashCode() { - return pc; + return pc | flagState; } public boolean equals(Object o) { - return ((o instanceof ARM_LazinessKey) && ((ARM_LazinessKey) o).pc == pc); + if (!(o instanceof ARM_LazinessKey)) + return false; + + ARM_LazinessKey otherKey = (ARM_LazinessKey)o; + return otherKey.pc == pc && otherKey.flagState == flagState; } - ARM_LazinessKey(int pc) { + ARM_LazinessKey(int pc, ARM_Laziness lazy) { this.pc = pc; + int tmpFlagState = lazy.flagValid & 0xF; + tmpFlagState |= (lazinessOperation.ordinal() + 1) << 4; + + this.flagState = (byte)tmpFlagState; } public String toString() { - return "0x" + Integer.toHexString(pc); + return String.format("0x%x (%d)", pc, flagState); } } + public ARM_Laziness() { + flagValid = 0xF; //all flags are valid + lazinessOperation = Operation.Add; + } + + private ARM_Laziness(ARM_Laziness other) { + set(other); + } + + public void setValid(Flag flag, boolean valid) { + flagValid |= 1 << flag.ordinal(); + } + + public boolean isValid(Flag flag) { + return (flagValid & (1 << flag.ordinal())) != 0; + } + + public void setAddOperation() { + flagValid = 0; // all flags are invalid + lazinessOperation = Operation.Add; + } + + public void setSubOperation() { + flagValid = 0; // all flags are invalid + lazinessOperation = Operation.Sub; + } + + public Operation getOperation() { + return lazinessOperation; + } + + public void setOperation(Operation lazinessOperation) { + this.lazinessOperation = lazinessOperation; + } + + public void set(ARM_Laziness other) { + flagValid = other.flagValid; + lazinessOperation = other.lazinessOperation; + } + @Override public Object clone() { - return new ARM_Laziness(); + return new ARM_Laziness(this); } @Override - public boolean equivalent(Laziness other) { - return other instanceof ARM_Laziness; + public boolean equivalent(Laziness o) { + if (!(o instanceof ARM_Laziness)) + return false; + + ARM_Laziness other = (ARM_Laziness)o; + return flagValid == other.flagValid && lazinessOperation == other.lazinessOperation; } @Override public Key makeKey(int pc) { - return new ARM_LazinessKey(pc); + return new ARM_LazinessKey(pc, this); } + @Override + public String toString() { + return "Operation: " + lazinessOperation + ", C:" + (isValid(Flag.Carry) ? "1" : "0") + + ", Z:" + (isValid(Flag.Zero) ? "1" : "0") + + ", N:" + (isValid(Flag.Negative) ? "1" : "0") + + ", O:" + (isValid(Flag.Overflow) ? "1" : "0"); + } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-07 22:28:53 UTC (rev 161) @@ -377,8 +377,9 @@ curBlock.deleteNormalOut(); curBlock.insertOut(nextBlock); curBlock.insertOut(block1); + OPT_Operand carryFlag = translator.arm2ir.readCarryFlag(translator.lazy); translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), carryFlag, new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); @@ -414,7 +415,7 @@ value = new OPT_IntConstantOperand(operand.getImmediate()); if (operand.getShiftAmount() != 0) { - OPT_RegisterOperand carryFlag = translator.arm2ir.getCarryFlag(); + OPT_RegisterOperand carryFlag = translator.arm2ir.writeCarryFlag(translator.lazy); OPT_Operand shifterCarryOut = new OPT_IntConstantOperand(((operand.getImmediate() & 0x80000000) != 0) ? 1 : 0); //otherwise there is no shifter carry out @@ -451,7 +452,7 @@ /** Returns the register that receives the shifte carry out*/ private OPT_RegisterOperand getShifterCarryOutTarget() { - return translator.arm2ir.getCarryFlag(); + return translator.arm2ir.writeCarryFlag(translator.lazy); } /** @@ -685,7 +686,7 @@ curBlock.insertOut(block1); curBlock.insertOut(nextBlock); translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, translator.arm2ir.readCarryFlag(translator.lazy), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); @@ -720,7 +721,7 @@ /** Return the instruction following this one or -1, if that is not yet known. */ int getSuccessor(int pc); } - + /** All ARM instructions that are supposed to be executed conditionally * are decorated with this decorator. * The decorator takes care of checking the individual condition and depending on it, executing the @@ -729,7 +730,7 @@ protected final ARM_Instruction conditionalInstruction; protected final Condition condition; - + /** Decorates an ARM interpreter instruction, by making it execute conditionally. */ protected ConditionalDecorator(ARM_Instruction i) { conditionalInstruction = i; @@ -738,132 +739,213 @@ public int getSuccessor(int pc) { - boolean thumbMode = (pc & 0x1) == 1; - return pc + (thumbMode ? 2 : 4); + if (assumeInstructionWillBeSkipped()) { + boolean thumbMode = (pc & 0x1) == 1; + return pc + (thumbMode ? 2 : 4); + } + else { + return conditionalInstruction.getSuccessor(pc); + } } public Condition getCondition() { return condition; } + /** + * Returns the probability that this conditional instruction will be skipped. + * + * @return + * The probability that this conditional instruction will be skipped. Returns -1, if this probability + * cannot be estimated. + */ + private float getSkipProbability() { + + if (DBT_Options.optimizeTranslationByProfiling) + return -1f; + + return ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); + } + + /** + * During the processing of this conditional instruction, shall we assume that it will be skipped? + * This is helpful to optimize the trace. + * + * @return + * True if it is likely that this instruction will be skipped. False otherwise. + */ + private boolean assumeInstructionWillBeSkipped() { + float skipProbability = getSkipProbability(); + + return (skipProbability == -1f || skipProbability > 0.5f); + } + + /** + conditionals are implemented easily: if the condition does not hold, then just + jump to the block following the conditional instruction. To do this, the following structure of + block is built: + + -------------------------------------------------------- + 1. block that checks the condition + -------------------------------------------------------- + 2. conditional instruction + -------------------------------------------------------- + 3. next instruction, when the instruction was not skipped + -------------------------------------------------------- + 4. next instruction, when it was skipped <- next block + -------------------------------------------------------- + + Note that the two last blocks are only necessary when laziness is used. Otherwise, the first of + them will remain empty. + */ public void translate() { - //conditionals are implemented easily: if the condition does not hold, then just - //jump to the block following the conditional instruction - OPT_BasicBlock nextInstruction = arm2ir.getNextBlock(); - OPT_BasicBlock condBlock = arm2ir.createBlockAfterCurrent(); - arm2ir.getCurrentBlock().deleteNormalOut(); - arm2ir.getCurrentBlock().insertOut(nextInstruction); - arm2ir.getCurrentBlock().insertOut(condBlock); + + OPT_BasicBlock blockThatChecksCondition = arm2ir.getCurrentBlock(); + OPT_BasicBlock nextInstruction_InstructionSkipped = arm2ir.getNextBlock(); + OPT_BasicBlock nextInstruction_InstructionNotSkipped = arm2ir.createBlockAfterCurrent(); + OPT_BasicBlock condInstructionBlock = arm2ir.createBlockAfterCurrent(); + + //prepare to translate the actual condition + arm2ir.setCurrentBlock(blockThatChecksCondition); + blockThatChecksCondition.deleteNormalOut(); + blockThatChecksCondition.insertOut(nextInstruction_InstructionSkipped); + blockThatChecksCondition.insertOut(condInstructionBlock); //Query the branch profile to get the probability that this instruction is going to get executed OPT_BranchProfileOperand profileOperand; - if (DBT_Options.optimizeTranslationByProfiling) { - float skipProbability = ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); + float skipProbability = getSkipProbability(); - if (skipProbability == -1 || skipProbability == 0.5f) { - profileOperand = new OPT_BranchProfileOperand(); - } - else if (skipProbability > 0.8f) { - profileOperand = OPT_BranchProfileOperand.always(); - condBlock.setInfrequent(); - } - else if (skipProbability > 0.5f) { - profileOperand = OPT_BranchProfileOperand.likely(); - condBlock.setInfrequent(); - } - else if (skipProbability < 0.2f) { - profileOperand = OPT_BranchProfileOperand.never(); - } - else { - profileOperand = OPT_BranchProfileOperand.unlikely(); - } + if (skipProbability == -1 || skipProbability == 0.5f) { + profileOperand = new OPT_BranchProfileOperand(); } + else if (skipProbability > 0.8f) { + profileOperand = OPT_BranchProfileOperand.always(); + condInstructionBlock.setInfrequent(); + } + else if (skipProbability > 0.5f) { + profileOperand = OPT_BranchProfileOperand.likely(); + condInstructionBlock.setInfrequent(); + } + else if (skipProbability < 0.2f) { + profileOperand = OPT_BranchProfileOperand.never(); + } else { - profileOperand = new OPT_BranchProfileOperand(); + profileOperand = OPT_BranchProfileOperand.unlikely(); } switch (condition) { case AL: - throw new RuntimeException("ARM32 instructions with a condition of AL (always) should not be decorated with a ConditionalDecorator."); + throw new RuntimeException("Unconditional instructions should not be decorated with a ConditionalDecorator."); case CC: //return !regs.isCarrySet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getCarryFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readCarryFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case CS: //return regs.isCarrySet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getCarryFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readCarryFlag(lazy), OPT_ConditionOperand.EQUAL()); break; case EQ: //return regs.isZeroSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getZeroFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readZeroFlag(lazy), OPT_ConditionOperand.EQUAL()); break; case GE: //return regs.isNegativeSet() == regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL(), arm2ir.getOverflowFlag()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.EQUAL(), arm2ir.readOverflowFlag(lazy)); break; case GT: - translateCondition_GT(nextInstruction, profileOperand); + translateCondition_GT(nextInstruction_InstructionSkipped, profileOperand); break; case HI: - translateCondition_HI(nextInstruction, profileOperand); + translateCondition_HI(nextInstruction_InstructionSkipped, profileOperand); break; case LE: - translateCondition_LE(nextInstruction, profileOperand); + translateCondition_LE(nextInstruction_InstructionSkipped, profileOperand); break; case LS: - translateCondition_LS(nextInstruction, profileOperand, condBlock); + translateCondition_LS(nextInstruction_InstructionSkipped, profileOperand, condInstructionBlock); break; case LT: //return regs.isNegativeSet() != regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.getOverflowFlag()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.readOverflowFlag(lazy)); break; case MI: //return regs.isNegativeSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.EQUAL()); break; case NE: //return !regs.isZeroSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getZeroFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readZeroFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case NV: //never execute this instruction - translateCondition(nextInstruction, profileOperand, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL()); break; case PL: //return !regs.isNegativeSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case VC: //return !regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getOverflowFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readOverflowFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case VS: //return regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getOverflowFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readOverflowFlag(lazy), OPT_ConditionOperand.EQUAL()); break; default: throw new RuntimeException("Unexpected condition code: " + condition); - } + } + + //Translate the conditional instruction first to see if the lazy state is changed by the + //conditional instruction + ARM_Laziness lazinessWhenInstructionSkipped = (ARM_Laziness)lazy.clone(); - arm2ir.setCurrentBlock(condBlock); + arm2ir.setCurrentBlock(condInstructionBlock); + arm2ir.setNextBlock(nextInstruction_InstructionNotSkipped); conditionalInstruction.translate(); + + int followingInstructionAddress = pc + (inThumb() ? 2 : 4); + + //yes it did, so we may need to translate the successor instruction twice + if (assumeInstructionWillBeSkipped()) { + + //Did the laziness change during the translation? + if (!lazy.equivalent(lazinessWhenInstructionSkipped)) { + //Modify block 3 so that it resolves the different laziness correctly + arm2ir.setCurrentBlock(nextInstruction_InstructionNotSkipped); + nextInstruction_InstructionNotSkipped.deleteNormalOut(); + arm2ir.appendBranch(followingInstructionAddress, lazy); + lazy.set(lazinessWhenInstructionSkipped); + } + + arm2ir.setNextBlock(nextInstruction_InstructionSkipped); + + } + else { + //Modify block 4 so that it resolves the different laziness correctly + arm2ir.setCurrentBlock(nextInstruction_InstructionSkipped); + nextInstruction_InstructionSkipped.deleteNormalOut(); + arm2ir.appendBranch(followingInstructionAddress, lazinessWhenInstructionSkipped); + + arm2ir.setNextBlock(nextInstruction_InstructionNotSkipped); + } } private void translateCondition(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_Operand operand, OPT_ConditionOperand condition) { @@ -878,8 +960,8 @@ private void translateCondition_HI(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isCarrySet() && !regs.isZeroSet(); - OPT_Operand carry = arm2ir.getCarryFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand carry = arm2ir.readCarryFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, carry, @@ -890,33 +972,20 @@ private void translateCondition_LS(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_BasicBlock actualInstruction) { //return !regs.isCarrySet() || regs.isZeroSet(); - OPT_Operand carry = arm2ir.getCarryFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand carry = arm2ir.readCarryFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getTempInt(0); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, carry, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); - -/* cond1.deleteNormalOut(); - cond1.insertOut(cond2); - cond1.insertOut(actualInstruction); - - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), carry, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), actualInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); - - arm2ir.setCurrentBlock(cond2); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), actualInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(Goto.create(GOTO, nextInstruction.makeJumpTarget())); - cond2.deleteNormalOut(); - cond2.insertOut(nextInstruction); - cond2.insertOut(actualInstruction);*/ } private void translateCondition_GT(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return (regs.isNegativeSet() == regs.isOverflowSet()) && !regs.isZeroSet(); - OPT_Operand negative = arm2ir.getNegativeFlag(); - OPT_Operand overflow = arm2ir.getOverflowFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand negative = arm2ir.readNegativeFlag(lazy); + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, negative, @@ -927,9 +996,9 @@ private void translateCondition_LE(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isZeroSet() || (regs.isNegativeSet() != regs.isOverflowSet()); - OPT_Operand negative = arm2ir.getNegativeFlag(); - OPT_Operand overflow = arm2ir.getOverflowFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand negative = arm2ir.readNegativeFlag(lazy); + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, negative, @@ -1021,21 +1090,8 @@ * The add's right-hand-side operator. */ protected final void setAddFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { - //set the carry flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), result.copy(), lhs.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); - //set the overflow flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs.copy(), rhs.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); - - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + arm2ir.appendAddFlags(lazy, result, lhs, rhs); } /** Sets the processor flags according to the result of subtracting <code>rhs</code> from <code>lhs</code>.*/ @@ -1077,22 +1133,8 @@ * The sub's right-hand-side operator. */ protected final void setSubFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { - //set the carry flag to not(Borrow) - OPT_ConditionOperand notBorrowFromSub = OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(); - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), lhs.copy(), rhs.copy(), notBorrowFromSub, new OPT_BranchProfileOperand())); - //set the overflow flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs.copy(), rhs.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); - - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + arm2ir.appendSubFlags(lazy, result, lhs, rhs); } public Condition getCondition() { @@ -1165,13 +1207,8 @@ protected final void setLogicalFlags(OPT_Operand result) { //the shifter carry out has already been set during the resolve-phase - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + //set the negative & zero flag + arm2ir.appendLogicalFlags(lazy, result); } } @@ -1287,7 +1324,7 @@ //Is the carry set at all? if not, just jump to addWithoutCarry arm2ir.appendInstruction(Binary.create(INT_ADD, result, operand1, operand2)); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.getCarryFlag(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), addWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.readCarryFlag(lazy), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), addWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(addWithCarry); //Yes, the carry flag is set. Pre-increase the result by one to account for the carry. @@ -1318,7 +1355,7 @@ //Is the carry set? if yes, just jump to subWithoutCarry arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2)); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), subWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.readCarryFlag(lazy), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), subWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(subWithCarry); //No, the carry flag is not set. That means, we have to use the carry within the subtraction (weird arm logic). @@ -1674,41 +1711,7 @@ //first translate the register write back translateWriteback(startAddress.copyRO(), nextAddress.copyRO()); - - //shall we switch to thumb mode? - /*OPT_BasicBlock finishInstruction = arm2ir.createBlockAfterCurrentNotInCFG(); - OPT_BasicBlock switchToARMBlock = arm2ir.createBlockAfterCurrentNotInCFG(); - OPT_BasicBlock switchToThumbBlock = arm2ir.createBlockAfterCurrentNotInCFG(); - - //Current block - OPT_BasicBlock currentBlock = arm2ir.getCurrentBlock(); - currentBlock.deleteNormalOut(); - currentBlock.insertOut(switchToARMBlock); - currentBlock.insertOut(switchToThumbBlock); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), regPC.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.BIT_TEST(), switchToThumbBlock.makeJumpTarget(), OPT_BranchProfileOperand.never())); - arm2ir.appendInstruction(Goto.create(GOTO, switchToARMBlock.makeJumpTarget())); - - //Yes, switch to thumb mode - arm2ir.setCurrentBlock(switchToThumbBlock); - switchToThumbBlock.insertOut(finishInstruction); - OPT_Instruction call_setThumbMode = createCallToRegisters("setThumbMode", "(Z)V", 1); - Call.setParam(call_setThumbMode, 1, new OPT_IntConstantOperand(1)); - arm2ir.appendCustomCall(call_setThumbMode); - arm2ir.appendInstruction(Goto.create(GOTO, finishInstruction.makeJumpTarget())); - //No, don't switch to thumb mode - arm2ir.setCurrentBlock(switchToARMBlock); - switchToARMBlock.insertOut(finishInstruction); - arm2ir.appendInstruction(Binary.create(INT_AND, regPC.copyRO(), regPC.copy(), new OPT_IntConstantOperand(0xFFFFFFFE))); - OPT_Instruction call_setArmMode = createCallToRegisters("setThumbMode", "(Z)V", 1); - Call.setParam(call_setArmMode, 1, new OPT_IntConstantOperand(0)); - arm2ir.appendCustomCall(call_setArmMode); - arm2ir.appendInstruction(Goto.create(GOTO, finishInstruction.makeJumpTarget())); - - //according to the APCS, these types of instructions are usually function returns - arm2ir.setCurrentBlock(finishInstruction); - arm2ir.appendBranch(regPC, lazy, BranchType.RETURN);*/ - arm2ir.appendBranch(regPC, lazy, BranchType.RETURN); return; } @@ -1940,13 +1943,8 @@ } if (i.updateConditionCodes) { - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copyRO(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copyRO(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + //set the negative & zero flag + arm2ir.appendLogicalFlags(lazy, result); } } @@ -2006,13 +2004,13 @@ } if (i.updateConditionCodes) { - //set the negative flag + //set the negative flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_LONG, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_LONG, arm2ir.writeNegativeFlag(lazy), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_LONG, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_LONG, arm2ir.writeZeroFlag(lazy), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } } @@ -2223,6 +2221,7 @@ //do we actually have to perform the rotation? arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), rotation.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.NOT_EQUAL(), rotationBlock.makeJumpTarget(), OPT_BranchProfileOperand.never())); arm2ir.appendInstruction(Goto.create(GOTO, remainderBlock.makeJumpTarget())); + arm2ir.getCurrentBlock().insertOut(remainderBlock); //in case we are performing the rotation... arm2ir.setCurrentBlock(rotationBlock); Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-07 22:28:53 UTC (rev 161) @@ -247,7 +247,7 @@ * dependencies (unknown branch targets etc.) have been resolved. This function is useful for * debug purposes. */ - protected void printTraceAfterCompletion() { + public void printTraceAfterCompletion() { printTraceAfterCompletionRequested = true; } @@ -283,18 +283,9 @@ printTraceAfterCompletionRequested = false; printNextBlocks(preFillBlock, 50); } + + ((DBT_Trace) gc.method).setNumberOfInstructions(numberOfInstructions); } - /* - protected final void maximizeBasicBlocks(OPT_IR ir) { - for (OPT_BasicBlock currBB = ir.cfg.firstInCodeOrder(); currBB != null;) { - if (currBB.mergeFallThrough(ir)) { - // don't advance currBB; it may have a new trivial fallthrough to - // swallow - } else { - currBB = currBB.nextBasicBlockInCodeOrder(); - } - } - }*/ /** @@ -759,8 +750,11 @@ * within the code cache c) The trace is already too long d) the branch is * supposedly a CALL or RETURN */ + + DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); + return DBT_Options.singleInstrTranslation == false - && ps.codeCache.tryGet(targetPc) == null && !shallTraceStop() + && (compiledTrace == null || compiledTrace.getNumberOfInstructions() > 20) && !shallTraceStop() && jump.type != BranchType.CALL && jump.type != BranchType.RETURN; } @@ -789,7 +783,7 @@ if (targetBB != null) return targetBB; - if (inlineBranchInstruction(targetPc, jump)) { + if (!inlineBranchInstruction(targetPc, jump)) { // Just exit the trace and continue at the target address in a new trace if (currentBlock.getNumberOfRealInstructions() != 0) { @@ -903,7 +897,7 @@ // Copy the value into the register specified by gc.resultReg. appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand( gc.resultReg, VM_TypeReference.Int), nextPc.copy())); - resolveLaziness(laziness); + resolveLaziness((Laziness)laziness.clone()); appendInstruction(Goto.create(GOTO, finishBlock.makeJumpTarget())); currentBlock.deleteNormalOut(); currentBlock.insertOut(finishBlock); @@ -1305,9 +1299,7 @@ */ public void appendInterpretedInstruction(int pc, Laziness lazy) { - if (lazy != null) - resolveLaziness(lazy); - + resolveLaziness(lazy); spillAllRegisters(); // Prepare a local variable of type Interpreter Modified: src/org/binarytranslator/vmInterface/DBT_Trace.java =================================================================== --- src/org/binarytranslator/vmInterface/DBT_Trace.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/vmInterface/DBT_Trace.java 2007-08-07 22:28:53 UTC (rev 161) @@ -97,6 +97,9 @@ */ public final int pc; + /** The number of guest instructions that have been compiled into this trace. */ + private int numberOfInstructions; + /** * In order to allow arbitrary calls within a trace, we have to store at which bytecode index * a method is called in which way. This class stores the necessary information. */ @@ -321,4 +324,12 @@ public int getBytecodeLength() { return 256; } + + public int getNumberOfInstructions() { + return numberOfInstructions; + } + + public void setNumberOfInstructions(int numberOfInstructions) { + this.numberOfInstructions = numberOfInstructions; + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-07 22:27:31
|
Revision: 160 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=160&view=rev Author: michael_baer Date: 2007-08-07 15:27:33 -0700 (Tue, 07 Aug 2007) Log Message: ----------- - Reverted removal of Pearcolator's custom OPT_Simplifier - Adapted to compile with recent JRVM Added Paths: ----------- ext/org/jikesrvm/compilers/opt/OPT_Simplifier.java Added: ext/org/jikesrvm/compilers/opt/OPT_Simplifier.java =================================================================== --- ext/org/jikesrvm/compilers/opt/OPT_Simplifier.java (rev 0) +++ ext/org/jikesrvm/compilers/opt/OPT_Simplifier.java 2007-08-07 22:27:33 UTC (rev 160) @@ -0,0 +1,3643 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.compilers.opt; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import org.jikesrvm.VM; +import static org.jikesrvm.VM_SizeConstants.BITS_IN_ADDRESS; +import static org.jikesrvm.VM_SizeConstants.BITS_IN_INT; +import static org.jikesrvm.VM_SizeConstants.BITS_IN_LONG; +import static org.jikesrvm.VM_SizeConstants.LOG_BYTES_IN_ADDRESS; +import org.jikesrvm.classloader.VM_Field; +import org.jikesrvm.classloader.VM_Method; +import org.jikesrvm.classloader.VM_Type; +import org.jikesrvm.classloader.VM_TypeReference; +import org.jikesrvm.compilers.opt.OPT_Simplifier.DefUseEffect; +import org.jikesrvm.compilers.opt.ir.Binary; +import org.jikesrvm.compilers.opt.ir.BooleanCmp; +import org.jikesrvm.compilers.opt.ir.BooleanCmp2; +import org.jikesrvm.compilers.opt.ir.BoundsCheck; +import org.jikesrvm.compilers.opt.ir.Call; +import org.jikesrvm.compilers.opt.ir.CondMove; +import org.jikesrvm.compilers.opt.ir.Empty; +import org.jikesrvm.compilers.opt.ir.GetField; +import org.jikesrvm.compilers.opt.ir.GuardedBinary; +import org.jikesrvm.compilers.opt.ir.GuardedUnary; +import org.jikesrvm.compilers.opt.ir.InstanceOf; +import org.jikesrvm.compilers.opt.ir.Load; +import org.jikesrvm.compilers.opt.ir.Move; +import org.jikesrvm.compilers.opt.ir.NullCheck; +import org.jikesrvm.compilers.opt.ir.OPT_AbstractRegisterPool; +import org.jikesrvm.compilers.opt.ir.OPT_AddressConstantOperand; +import org.jikesrvm.compilers.opt.ir.OPT_BranchProfileOperand; +import org.jikesrvm.compilers.opt.ir.OPT_CodeConstantOperand; +import org.jikesrvm.compilers.opt.ir.OPT_ConditionOperand; +import org.jikesrvm.compilers.opt.ir.OPT_ConstantOperand; +import org.jikesrvm.compilers.opt.ir.OPT_IRTools; +import org.jikesrvm.compilers.opt.ir.OPT_Instruction; +import org.jikesrvm.compilers.opt.ir.OPT_IntConstantOperand; +import org.jikesrvm.compilers.opt.ir.OPT_MethodOperand; +import org.jikesrvm.compilers.opt.ir.OPT_NullConstantOperand; +import org.jikesrvm.compilers.opt.ir.OPT_ObjectConstantOperand; +import org.jikesrvm.compilers.opt.ir.OPT_Operand; +import org.jikesrvm.compilers.opt.ir.OPT_Operator; +import org.jikesrvm.compilers.opt.ir.OPT_OperatorNames; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.*; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ADDR_2INT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ADDR_2LONG_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ARRAYLENGTH_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_ADDR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_DOUBLE; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_FLOAT; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_INT; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_INT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_LONG; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_NOT; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_NOT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOUNDS_CHECK_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CALL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CHECKCAST_NOTNULL; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CHECKCAST_NOTNULL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CHECKCAST_UNRESOLVED_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CHECKCAST_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_2FLOAT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_2INT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_2LONG_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_ADD_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_AS_LONG_BITS_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_CMPG_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_CMPL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_COND_MOVE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_DIV_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_MOVE; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_MUL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_NEG; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_NEG_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_REM_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_SUB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_2DOUBLE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_2INT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_2LONG_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_ADD_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_AS_INT_BITS_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_CMPG_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_CMPL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_COND_MOVE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_DIV_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_MOVE; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_MUL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_NEG; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_NEG_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_REM_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_SUB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GETFIELD_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_CLASS_TIB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_DOES_IMPLEMENT_FROM_TIB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_OBJ_TIB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_SUPERCLASS_IDS_FROM_TIB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_TYPE_FROM_TIB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GUARD_COMBINE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GUARD_COND_MOVE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GUARD_MOVE; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INSTANCEOF_NOTNULL; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INSTANCEOF_NOTNULL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INSTANCEOF_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2ADDRSigExt; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2ADDRSigExt_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2ADDRZerExt_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2BYTE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2DOUBLE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2FLOAT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2LONG_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2SHORT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2USHORT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_ADD; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_ADD_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_AND_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_BITS_AS_FLOAT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_COND_MOVE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_DIV_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_MOVE; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_MUL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_NEG; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_NEG_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_NOT; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_NOT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_OR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_REM_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_SHL; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_SHL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_SHR; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_SHR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_SUB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_USHR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_XOR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_ZERO_CHECK_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2ADDR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2DOUBLE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2FLOAT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2INT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_ADD; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_ADD_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_AND_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_BITS_AS_DOUBLE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_CMP_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_COND_MOVE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_DIV_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_MOVE; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_MUL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_NEG; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_NEG_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_NOT; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_NOT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_OR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_REM_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SHL; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SHL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SHR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SUB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_USHR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_XOR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_ZERO_CHECK_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.MUST_IMPLEMENT_INTERFACE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.NOP; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.NULL_CHECK_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.OBJARRAY_STORE_CHECK_NOTNULL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.OBJARRAY_STORE_CHECK_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_ADD; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_ADD_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_AND_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_COND_MOVE_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_LOAD_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_MOVE; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_NEG; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_NOT; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_NOT_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_OR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_SHL; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_SHL_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_SHR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_SUB_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_USHR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_XOR_opcode; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.TRAP; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.TRAP_IF; +import static org.jikesrvm.compilers.opt.ir.OPT_Operators.TRAP_IF_opcode; +import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; +import org.jikesrvm.compilers.opt.ir.OPT_TIBConstantOperand; +import org.jikesrvm.compilers.opt.ir.OPT_TrapCodeOperand; +import org.jikesrvm.compilers.opt.ir.OPT_TrueGuardOperand; +import org.jikesrvm.compilers.opt.ir.OPT_TypeOperand; +import org.jikesrvm.compilers.opt.ir.OPT_UnreachableOperand; +import org.jikesrvm.compilers.opt.ir.StoreCheck; +import org.jikesrvm.compilers.opt.ir.Trap; +import org.jikesrvm.compilers.opt.ir.TrapIf; +import org.jikesrvm.compilers.opt.ir.TypeCheck; +import org.jikesrvm.compilers.opt.ir.Unary; +import org.jikesrvm.compilers.opt.ir.ZeroCheck; +import org.jikesrvm.objectmodel.VM_TIBLayoutConstants; +import org.jikesrvm.runtime.VM_Reflection; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.Word; + +/** + * A constant folder, strength reducer and axiomatic simplifier. + * + * <p> This module performs no analysis, it simply attempts to + * simplify the instruction as is. The intent is that + * analysis modules can call this transformation engine, allowing us to + * share the tedious simplification code among multiple analysis modules. + * + * <p> NOTE: For maintainability purposes, I've intentionally avoided being + * clever about combining 'similar' operators together into a combined case + * of the main switch switch statement. Also, operators are in sorted ordered + * within each major grouping. Please maintain this coding style. + * I'd rather have this module be 2000 lines of obviously correct code than + * 500 lines of clever code. + */ +public abstract class OPT_Simplifier extends OPT_IRTools { + // NOTE: The convention is that constant folding is controlled based + // on the type of the result of the operator, not the type of its inputs. + /** + * Constant fold integer operations? + */ + public static final boolean CF_INT = true; + /** + * Constant fold address operations? + */ + public static final boolean CF_LONG = true; + + /** + * Constant fold address operations? + */ + public static final boolean CF_ADDR = true; + + /** + * Constant fold float operations? Default is true, flip to avoid + * consuming precious JTOC slots to hold new constant values. + */ + public static final boolean CF_FLOAT = true; + /** + * Constant fold double operations? Default is true, flip to avoid + * consuming precious JTOC slots to hold new constant values. + */ + public static final boolean CF_DOUBLE = true; + /** + * Constant fold field operations? Default is true, flip to avoid + * consuming precious JTOC slots to hold new constant values. + */ + public static final boolean CF_FIELDS = true; + + /** + * Constant fold TIB operations? Default is true, flip to avoid + * consuming precious JTOC slots to hold new constant values. + */ + public static final boolean CF_TIB = true; + + /** + * Effect of the simplification on Def-Use chains + */ + public enum DefUseEffect { + /** + * Enumeration value to indicate an operation is unchanged, + * although the order of operands may have been canonicalized and + * type information strengthened. + */ + UNCHANGED, + /** + * Enumeration value to indicate an operation has been replaced by + * a move instruction with a constant right hand side. + */ + MOVE_FOLDED, + /** + * Enumeration value to indicate an operation has been replaced by + * a move instruction with a non-constant right hand side. + */ + MOVE_REDUCED, + /** + * Enumeration value to indicate an operation has been replaced by + * an unconditional trap instruction. + */ + TRAP_REDUCED, + /** + * Enumeration value to indicate an operation has been replaced by + * a cheaper, but non-move instruction. + */ + REDUCED + } + + /** + * Given an instruction, attempt to simplify it. + * The instruction will be mutated in place. + * + * <p> We don't deal with branching operations here -- + * doing peephole optimizations of branches + * is the job of a separate module. + * + * @param regpool register pool in case simplification requires a temporary register + * @param s the instruction to simplify + * @return one of UNCHANGED, MOVE_FOLDED, MOVE_REDUCED, TRAP_REDUCED, REDUCED + */ + public static DefUseEffect simplify(OPT_AbstractRegisterPool regpool, OPT_Instruction s) { + DefUseEffect result; + char opcode = s.getOpcode(); + switch (opcode) { + //////////////////// + // GUARD operations + //////////////////// + case GUARD_COMBINE_opcode: + result = guardCombine(s); + break; + //////////////////// + // TRAP operations + //////////////////// + case TRAP_IF_opcode: + result = trapIf(s); + break; + case NULL_CHECK_opcode: + result = nullCheck(s); + break; + case INT_ZERO_CHECK_opcode: + result = intZeroCheck(s); + break; + case LONG_ZERO_CHECK_opcode: + result = longZeroCheck(s); + break; + case CHECKCAST_opcode: + result = checkcast(s); + break; + case CHECKCAST_UNRESOLVED_opcode: + result = checkcast(s); + break; + case CHECKCAST_NOTNULL_opcode: + result = checkcastNotNull(s); + break; + case INSTANCEOF_opcode: + result = instanceOf(s); + break; + case INSTANCEOF_NOTNULL_opcode: + result = instanceOfNotNull(s); + break; + case OBJARRAY_STORE_CHECK_opcode: + result = objarrayStoreCheck(s); + break; + case OBJARRAY_STORE_CHECK_NOTNULL_opcode: + result = objarrayStoreCheckNotNull(s); + break; + case MUST_IMPLEMENT_INTERFACE_opcode: + result = mustImplementInterface(s); + break; + //////////////////// + // Conditional moves + //////////////////// + case INT_COND_MOVE_opcode: + result = intCondMove(s); + break; + case LONG_COND_MOVE_opcode: + result = longCondMove(s); + break; + case FLOAT_COND_MOVE_opcode: + result = floatCondMove(s); + break; + case DOUBLE_COND_MOVE_opcode: + result = doubleCondMove(s); + break; + case REF_COND_MOVE_opcode: + result = refCondMove(s); + break; + case GUARD_COND_MOVE_opcode: + result = guardCondMove(s); + break; + //////////////////// + // INT ALU operations + //////////////////// + case BOOLEAN_NOT_opcode: + result = booleanNot(s); + break; + case BOOLEAN_CMP_INT_opcode: + result = booleanCmpInt(s); + break; + case BOOLEAN_CMP_ADDR_opcode: + result = booleanCmpAddr(s); + break; + case BOOLEAN_CMP2_INT_OR_opcode: + result = booleanCmp2IntOr(s); + break; + // case BOOLEAN_CMP2_INT_AND: + // result = booleanCmp2IntAnd(s); + // break; + case INT_ADD_opcode: + result = intAdd(s); + break; + case INT_AND_opcode: + result = intAnd(s); + break; + case INT_DIV_opcode: + result = intDiv(s); + break; + case INT_MUL_opcode: + result = intMul(regpool, s); + break; + case INT_NEG_opcode: + result = intNeg(s); + break; + case INT_NOT_opcode: + result = intNot(s); + break; + case INT_OR_opcode: + result = intOr(s); + break; + case INT_REM_opcode: + result = intRem(s); + break; + case INT_SHL_opcode: + result = intShl(s); + break; + case INT_SHR_opcode: + result = intShr(s); + break; + case INT_SUB_opcode: + result = intSub(s); + break; + case INT_USHR_opcode: + result = intUshr(s); + break; + case INT_XOR_opcode: + result = intXor(s); + break; + //////////////////// + // WORD ALU operations + //////////////////// + case REF_ADD_opcode: + result = refAdd(s); + break; + case REF_AND_opcode: + result = refAnd(s); + break; + case REF_SHL_opcode: + result = refShl(s); + break; + case REF_SHR_opcode: + result = refShr(s); + break; + case REF_NOT_opcode: + result = refNot(s); + break; + case REF_OR_opcode: + result = refOr(s); + break; + case REF_SUB_opcode: + result = refSub(s); + break; + case REF_USHR_opcode: + result = refUshr(s); + break; + case REF_XOR_opcode: + result = refXor(s); + break; + //////////////////// + // LONG ALU operations + //////////////////// + case LONG_ADD_opcode: + result = longAdd(s); + break; + case LONG_AND_opcode: + result = longAnd(s); + break; + case LONG_CMP_opcode: + result = longCmp(s); + break; + case LONG_DIV_opcode: + result = longDiv(s); + break; + case LONG_MUL_opcode: + result = longMul(regpool, s); + break; + case LONG_NEG_opcode: + result = longNeg(s); + break; + case LONG_NOT_opcode: + result = longNot(s); + break; + case LONG_OR_opcode: + result = longOr(s); + break; + case LONG_REM_opcode: + result = longRem(s); + break; + case LONG_SHL_opcode: + result = longShl(s); + break; + case LONG_SHR_opcode: + result = longShr(s); + break; + case LONG_SUB_opcode: + result = longSub(s); + break; + case LONG_USHR_opcode: + result = longUshr(s); + break; + case LONG_XOR_opcode: + result = longXor(s); + break; + //////////////////// + // FLOAT ALU operations + //////////////////// + case FLOAT_ADD_opcode: + result = floatAdd(s); + break; + case FLOAT_CMPG_opcode: + result = floatCmpg(s); + break; + case FLOAT_CMPL_opcode: + result = floatCmpl(s); + break; + case FLOAT_DIV_opcode: + result = floatDiv(s); + break; + case FLOAT_MUL_opcode: + result = floatMul(s); + break; + case FLOAT_NEG_opcode: + result = floatNeg(s); + break; + case FLOAT_REM_opcode: + result = floatRem(s); + break; + case FLOAT_SUB_opcode: + result = floatSub(s); + break; + //////////////////// + // DOUBLE ALU operations + //////////////////// + case DOUBLE_ADD_opcode: + result = doubleAdd(s); + break; + case DOUBLE_CMPG_opcode: + result = doubleCmpg(s); + break; + case DOUBLE_CMPL_opcode: + result = doubleCmpl(s); + break; + case DOUBLE_DIV_opcode: + result = doubleDiv(s); + break; + case DOUBLE_MUL_opcode: + result = doubleMul(s); + break; + case DOUBLE_NEG_opcode: + result = doubleNeg(s); + break; + case DOUBLE_REM_opcode: + result = doubleRem(s); + break; + case DOUBLE_SUB_opcode: + result = doubleSub(s); + break; + //////////////////// + // CONVERSION operations + //////////////////// + case DOUBLE_2FLOAT_opcode: + result = double2Float(s); + break; + case DOUBLE_2INT_opcode: + result = double2Int(s); + break; + case DOUBLE_2LONG_opcode: + result = double2Long(s); + break; + case DOUBLE_AS_LONG_BITS_opcode: + result = doubleAsLongBits(s); + break; + case INT_2DOUBLE_opcode: + result = int2Double(s); + break; + case INT_2BYTE_opcode: + result = int2Byte(s); + break; + case INT_2USHORT_opcode: + result = int2UShort(s); + break; + case INT_2FLOAT_opcode: + result = int2Float(s); + break; + case INT_2LONG_opcode: + result = int2Long(s); + break; + case INT_2ADDRSigExt_opcode: + result = int2AddrSigExt(s); + break; + case INT_2ADDRZerExt_opcode: + result = int2AddrZerExt(s); + break; + case LONG_2ADDR_opcode: + result = long2Addr(s); + break; + case INT_2SHORT_opcode: + result = int2Short(s); + break; + case INT_BITS_AS_FLOAT_opcode: + result = intBitsAsFloat(s); + break; + case ADDR_2INT_opcode: + result = addr2Int(s); + break; + case ADDR_2LONG_opcode: + result = addr2Long(s); + break; + case FLOAT_2DOUBLE_opcode: + result = float2Double(s); + break; + case FLOAT_2INT_opcode: + result = float2Int(s); + break; + case FLOAT_2LONG_opcode: + result = float2Long(s); + break; + case FLOAT_AS_INT_BITS_opcode: + result = floatAsIntBits(s); + break; + case LONG_2FLOAT_opcode: + result = long2Float(s); + break; + case LONG_2INT_opcode: + result = long2Int(s); + break; + case LONG_2DOUBLE_opcode: + result = long2Double(s); + break; + case LONG_BITS_AS_DOUBLE_opcode: + result = longBitsAsDouble(s); + break; + //////////////////// + // Field operations + //////////////////// + case ARRAYLENGTH_opcode: + result = arrayLength(s); + break; + case BOUNDS_CHECK_opcode: + result = boundsCheck(s); + break; + case CALL_opcode: + result = call(s); + break; + case GETFIELD_opcode: + result = getField(s); + break; + case GET_OBJ_TIB_opcode: + result = getObjTib(s); + break; + case GET_CLASS_TIB_opcode: + result = getClassTib(s); + break; + case GET_TYPE_FROM_TIB_opcode: + result = getTypeFromTib(s); + break; + case GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode: + result = getArrayElementTibFromTib(s); + break; + case GET_SUPERCLASS_IDS_FROM_TIB_opcode: + result = getSuperclassIdsFromTib(s); + break; + case GET_DOES_IMPLEMENT_FROM_TIB_opcode: + result = getDoesImplementFromTib(s); + break; + case REF_LOAD_opcode: + result = refLoad(s); + break; + default: + result = DefUseEffect.UNCHANGED; + } + if (VM.VerifyAssertions) { + switch (result) { + case MOVE_FOLDED: + // Check move has constant RHS + VM._assert(Move.conforms(s) && (Move.getVal(s) instanceof OPT_ConstantOperand), + "RHS of move " + + s + + " should be constant during simplification of " + + OPT_OperatorNames.operatorName[opcode]); + break; + case MOVE_REDUCED: + // Check move has non-constant RHS + VM._assert(Move.conforms(s) && !(Move.getVal(s) instanceof OPT_ConstantOperand), + "RHS of move " + + s + + " shouldn't be constant during simplification of " + + OPT_OperatorNames.operatorName[opcode]); + break; + default: + // Nothing to check + } + } + return result; + } + + private static DefUseEffect guardCombine(OPT_Instruction s) { + OPT_Operand op1 = Binary.getVal1(s); + OPT_Operand op2 = Binary.getVal2(s); + if (op1.similar(op2) || (op2 instanceof OPT_TrueGuardOperand)) { + Move.mutate(s, GUARD_MOVE, Binary.getClearResult(s), op1); + if (op1 instanceof OPT_TrueGuardOperand) { + // BOTH true guards: FOLD + return DefUseEffect.MOVE_FOLDED; + } else { + // ONLY OP2 IS TrueGuard: MOVE REDUCE + return DefUseEffect.MOVE_REDUCED; + } + } else if (op1 instanceof OPT_TrueGuardOperand) { + // ONLY OP1 IS TrueGuard: MOVE REDUCE + Move.mutate(s, GUARD_MOVE, Binary.getClearResult(s), op2); + return DefUseEffect.MOVE_REDUCED; + } else { + return DefUseEffect.UNCHANGED; + } + } + + private static DefUseEffect trapIf(OPT_Instruction s) { + { + OPT_Operand op1 = TrapIf.getVal1(s); + OPT_Operand op2 = TrapIf.getVal2(s); + if (op1.isConstant()) { + if (op2.isConstant()) { + int willTrap = TrapIf.getCond(s).evaluate(op1, op2); + if (willTrap == OPT_ConditionOperand.TRUE) { + Trap.mutate(s, TRAP, TrapIf.getClearGuardResult(s), TrapIf.getClearTCode(s)); + return DefUseEffect.TRAP_REDUCED; + } else if (willTrap == OPT_ConditionOperand.FALSE) { + Move.mutate(s, GUARD_MOVE, TrapIf.getClearGuardResult(s), TG()); + return DefUseEffect.MOVE_FOLDED; + } + } else { + // canonicalize + TrapIf.mutate(s, + TRAP_IF, + TrapIf.getClearGuardResult(s), + TrapIf.getClearVal2(s), + TrapIf.getClearVal1(s), + TrapIf.getClearCond(s).flipOperands(), + TrapIf.getClearTCode(s)); + } + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect nullCheck(OPT_Instruction s) { + OPT_Operand ref = NullCheck.getRef(s); + if (ref.isNullConstant() || (ref.isAddressConstant() && ref.asAddressConstant().value.isZero())) { + Trap.mutate(s, TRAP, NullCheck.getClearGuardResult(s), OPT_TrapCodeOperand.NullPtr()); + return DefUseEffect.TRAP_REDUCED; + } else if (ref.isConstant()) { + // object, string, class or non-null address constant + + // Make the slightly suspect assumption that all non-zero address + // constants are actually valid pointers. Not necessarily true, + // but unclear what else we can do. + Move.mutate(s, GUARD_MOVE, NullCheck.getClearGuardResult(s), TG()); + return DefUseEffect.MOVE_FOLDED; + } else { + return DefUseEffect.UNCHANGED; + } + } + + private static DefUseEffect intZeroCheck(OPT_Instruction s) { + { + OPT_Operand op = ZeroCheck.getValue(s); + if (op.isIntConstant()) { + int val = op.asIntConstant().value; + if (val == 0) { + Trap.mutate(s, TRAP, ZeroCheck.getClearGuardResult(s), OPT_TrapCodeOperand.DivByZero()); + return DefUseEffect.TRAP_REDUCED; + } else { + Move.mutate(s, GUARD_MOVE, ZeroCheck.getClearGuardResult(s), TG()); + return DefUseEffect.MOVE_FOLDED; + } + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect longZeroCheck(OPT_Instruction s) { + { + OPT_Operand op = ZeroCheck.getValue(s); + if (op.isLongConstant()) { + long val = op.asLongConstant().value; + if (val == 0L) { + Trap.mutate(s, TRAP, ZeroCheck.getClearGuardResult(s), OPT_TrapCodeOperand.DivByZero()); + return DefUseEffect.TRAP_REDUCED; + } else { + Move.mutate(s, GUARD_MOVE, ZeroCheck.getClearGuardResult(s), TG()); + return DefUseEffect.MOVE_FOLDED; + } + } + } + return DefUseEffect.UNCHANGED; + } + private static DefUseEffect checkcast(OPT_Instruction s) { + OPT_Operand ref = TypeCheck.getRef(s); + if (ref.isNullConstant()) { + Empty.mutate(s, NOP); + return DefUseEffect.REDUCED; + } else if (ref.isConstant()) { + s.operator = CHECKCAST_NOTNULL; + return checkcastNotNull(s); + } else { + VM_TypeReference lhsType = TypeCheck.getType(s).getTypeRef(); + VM_TypeReference rhsType = ref.getType(); + byte ans = OPT_ClassLoaderProxy.includesType(lhsType, rhsType); + if (ans == OPT_Constants.YES) { + Empty.mutate(s, NOP); + return DefUseEffect.REDUCED; + } else { + // NOTE: OPT_Constants.NO can't help us because (T)null always succeeds + return DefUseEffect.UNCHANGED; + } + } + } + + private static DefUseEffect checkcastNotNull(OPT_Instruction s) { + OPT_Operand ref = TypeCheck.getRef(s); + VM_TypeReference lhsType = TypeCheck.getType(s).getTypeRef(); + VM_TypeReference rhsType = ref.getType(); + byte ans = OPT_ClassLoaderProxy.includesType(lhsType, rhsType); + if (ans == OPT_Constants.YES) { + Empty.mutate(s, NOP); + return DefUseEffect.REDUCED; + } else if (ans == OPT_Constants.NO) { + VM_Type rType = rhsType.peekType(); + if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { + // only final (or precise) rhs types can be optimized since rhsType may be conservative + Trap.mutate(s, TRAP, null, OPT_TrapCodeOperand.CheckCast()); + return DefUseEffect.TRAP_REDUCED; + } else { + return DefUseEffect.UNCHANGED; + } + } else { + return DefUseEffect.UNCHANGED; + } + } + private static DefUseEffect instanceOf(OPT_Instruction s) { + OPT_Operand ref = InstanceOf.getRef(s); + if (ref.isNullConstant()) { + Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0)); + return DefUseEffect.MOVE_FOLDED; + } else if (ref.isConstant()) { + s.operator = INSTANCEOF_NOTNULL; + return instanceOfNotNull(s); + } else { + VM_TypeReference lhsType = InstanceOf.getType(s).getTypeRef(); + VM_TypeReference rhsType = ref.getType(); + byte ans = OPT_ClassLoaderProxy.includesType(lhsType, rhsType); + // NOTE: OPT_Constants.YES doesn't help because ref may be null and null instanceof T is false + if (ans == OPT_Constants.NO) { + VM_Type rType = rhsType.peekType(); + if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { + // only final (or precise) rhs types can be optimized since rhsType may be conservative + Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0)); + return DefUseEffect.MOVE_FOLDED; + } else { + return DefUseEffect.UNCHANGED; + } + } else { + return DefUseEffect.UNCHANGED; + } + } + } + + private static DefUseEffect instanceOfNotNull(OPT_Instruction s) { + { + OPT_Operand ref = InstanceOf.getRef(s); + VM_TypeReference lhsType = InstanceOf.getType(s).getTypeRef(); + VM_TypeReference rhsType = ref.getType(); + byte ans = OPT_ClassLoaderProxy.includesType(lhsType, rhsType); + if (ans == OPT_Constants.YES) { + Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(1)); + return DefUseEffect.MOVE_FOLDED; + } else if (ans == OPT_Constants.NO) { + VM_Type rType = rhsType.peekType(); + if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { + // only final (or precise) rhs types can be optimized since rhsType may be conservative + Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0)); + return DefUseEffect.MOVE_FOLDED; + } + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect objarrayStoreCheck(OPT_Instruction s) { + OPT_Operand val = StoreCheck.getVal(s); + if (val.isNullConstant()) { + // Writing null into an array is trivially safe + Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); + return DefUseEffect.MOVE_REDUCED; + } else { + OPT_Operand ref = StoreCheck.getRef(s); + VM_TypeReference arrayTypeRef = ref.getType(); + VM_Type typeOfIMElem = arrayTypeRef.getInnermostElementType().peekType(); + if (typeOfIMElem != null) { + VM_Type typeOfVal = val.getType().peekType(); + if ((typeOfIMElem == typeOfVal) && (typeOfIMElem.isPrimitiveType() || typeOfIMElem.asClass().isFinal())) { + // Writing something of a final type to an array of that + // final type is safe + Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); + return DefUseEffect.MOVE_REDUCED; + } + } + if (ref.isConstant() && (arrayTypeRef == VM_TypeReference.JavaLangObjectArray)) { + // We know this to be an array of objects so any store must + // be safe + Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); + return DefUseEffect.MOVE_REDUCED; + } + if (val.isConstant() && ref.isConstant()) { + // writing a constant value into a constant array + byte ans = OPT_ClassLoaderProxy.includesType(arrayTypeRef.getArrayElementType(), val.getType()); + if (ans == OPT_Constants.YES) { + // all stores should succeed + Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); + return DefUseEffect.MOVE_REDUCED; + } else if (ans == OPT_Constants.NO) { + // all stores will fail + Trap.mutate(s, TRAP, StoreCheck.getClearGuardResult(s), OPT_TrapCodeOperand.StoreCheck()); + return DefUseEffect.TRAP_REDUCED; + } + } + return DefUseEffect.UNCHANGED; + } + } + + private static DefUseEffect objarrayStoreCheckNotNull(OPT_Instruction s) { + OPT_Operand val = StoreCheck.getVal(s); + OPT_Operand ref = StoreCheck.getRef(s); + VM_TypeReference arrayTypeRef = ref.getType(); + VM_Type typeOfIMElem = arrayTypeRef.getInnermostElementType().peekType(); + if (typeOfIMElem != null) { + VM_Type typeOfVal = val.getType().peekType(); + if ((typeOfIMElem == typeOfVal) && (typeOfIMElem.isPrimitiveType() || typeOfIMElem.asClass().isFinal())) { + // Writing something of a final type to an array of that + // final type is safe + Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); + return DefUseEffect.MOVE_REDUCED; + } + } + if (ref.isConstant() && (arrayTypeRef == VM_TypeReference.JavaLangObjectArray)) { + // We know this to be an array of objects so any store must + // be safe + Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); + return DefUseEffect.MOVE_REDUCED; + } + if (val.isConstant() && ref.isConstant()) { + // writing a constant value into a constant array + byte ans = OPT_ClassLoaderProxy.includesType(arrayTypeRef.getArrayElementType(), val.getType()); + if (ans == OPT_Constants.YES) { + // all stores should succeed + Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); + return DefUseEffect.MOVE_REDUCED; + } else if (ans == OPT_Constants.NO) { + // all stores will fail + Trap.mutate(s, TRAP, StoreCheck.getClearGuardResult(s), OPT_TrapCodeOperand.StoreCheck()); + return DefUseEffect.TRAP_REDUCED; + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect mustImplementInterface(OPT_Instruction s) { + OPT_Operand ref = TypeCheck.getRef(s); + if (ref.isNullConstant()) { + // Possible sitatution from constant propagation. This operation + // is really a nop as a null_check should have happened already + Trap.mutate(s, TRAP, null, OPT_TrapCodeOperand.NullPtr()); + return DefUseEffect.TRAP_REDUCED; + } else { + VM_TypeReference lhsType = TypeCheck.getType(s).getTypeRef(); // the interface that must be implemented + VM_TypeReference rhsType = ref.getType(); // our type + byte ans = OPT_ClassLoaderProxy.includesType(lhsType, rhsType); + if (ans == OPT_Constants.YES) { + Empty.mutate(s, NOP); + return DefUseEffect.REDUCED; + } else if (ans == OPT_Constants.NO) { + VM_Type rType = rhsType.peekType(); + if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { + // only final (or precise) rhs types can be optimized since rhsType may be conservative + Trap.mutate(s, TRAP, null, OPT_TrapCodeOperand.MustImplement()); + return DefUseEffect.TRAP_REDUCED; + } + } + return DefUseEffect.UNCHANGED; + } + } + + private static DefUseEffect intCondMove(OPT_Instruction s) { + { + OPT_Operand val1 = CondMove.getVal1(s); + OPT_Operand val2 = CondMove.getVal2(s); + int cond = CondMove.getCond(s).evaluate(val1, val2); + if (cond != OPT_ConditionOperand.UNKNOWN) { + // BOTH CONSTANTS OR SIMILAR: FOLD + OPT_Operand val = + (cond == OPT_ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); + Move.mutate(s, INT_MOVE, CondMove.getClearResult(s), val); + return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + if (val1.isConstant() && !val2.isConstant()) { + // Canonicalize by switching operands and fliping code. + OPT_Operand tmp = CondMove.getClearVal1(s); + CondMove.setVal1(s, CondMove.getClearVal2(s)); + CondMove.setVal2(s, tmp); + CondMove.getCond(s).flipOperands(); + } + OPT_Operand tv = CondMove.getTrueValue(s); + OPT_Operand fv = CondMove.getFalseValue(s); + if (tv.similar(fv)) { + Move.mutate(s, INT_MOVE, CondMove.getClearResult(s), tv); + return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + if (tv.isIntConstant() && fv.isIntConstant() && !CondMove.getCond(s).isFLOATINGPOINT()) { + int itv = tv.asIntConstant().value; + int ifv = fv.asIntConstant().value; + OPT_Operator op = null; + if (val1.isLong()) { + op = BOOLEAN_CMP_LONG; + } else if (val1.isFloat()) { + op = BOOLEAN_CMP_FLOAT; + } else if (val1.isDouble()) { + op = BOOLEAN_CMP_DOUBLE; + } else { + op = BOOLEAN_CMP_INT; + } + if (itv == 1 && ifv == 0) { + BooleanCmp.mutate(s, + op, + CondMove.getClearResult(s), + CondMove.getClearVal1(s), + CondMove.getClearVal2(s), + CondMove.getClearCond(s), + new OPT_BranchProfileOperand()); + return DefUseEffect.REDUCED; + } + if (itv == 0 && ifv == 1) { + BooleanCmp.mutate(s, + op, + CondMove.getClearResult(s), + CondMove.getClearVal1(s), + CondMove.getClearVal2(s), + CondMove.getClearCond(s).flipCode(), + new OPT_BranchProfileOperand()); + return DefUseEffect.REDUCED; + } + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect longCondMove(OPT_Instruction s) { + { + OPT_Operand val1 = CondMove.getVal1(s); + OPT_Operand val2 = CondMove.getVal2(s); + int cond = CondMove.getCond(s).evaluate(val1, val2); + if (cond != OPT_ConditionOperand.UNKNOWN) { + // BOTH CONSTANTS OR SIMILAR: FOLD + OPT_Operand val = + (cond == OPT_ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); + Move.mutate(s, LONG_MOVE, CondMove.getClearResult(s), val); + return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + if (val1.isConstant() && !val2.isConstant()) { + // Canonicalize by switching operands and fliping code. + OPT_Operand tmp = CondMove.getClearVal1(s); + CondMove.setVal1(s, CondMove.getClearVal2(s)); + CondMove.setVal2(s, tmp); + CondMove.getCond(s).flipOperands(); + } + OPT_Operand tv = CondMove.getTrueValue(s); + OPT_Operand fv = CondMove.getFalseValue(s); + if (tv.similar(fv)) { + Move.mutate(s, LONG_MOVE, CondMove.getClearResult(s), tv); + return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + if (tv.isLongConstant() && fv.isLongConstant() && !CondMove.getCond(s).isFLOATINGPOINT()) { + long itv = tv.asLongConstant().value; + long ifv = fv.asLongConstant().value; + OPT_Operator op = null; + if (val1.isLong()) { + op = BOOLEAN_CMP_LONG; + } else if (val1.isFloat()) { + op = BOOLEAN_CMP_FLOAT; + } else if (val1.isDouble()) { + op = BOOLEAN_CMP_DOUBLE; + } else { + op = BOOLEAN_CMP_INT; + } + if (itv == 1 && ifv == 0) { + BooleanCmp.mutate(s, + op, + CondMove.getClearResult(s), + CondMove.getClearVal1(s), + CondMove.getClearVal2(s), + CondMove.getClearCond(s), + new OPT_BranchProfileOperand()); + return DefUseEffect.REDUCED; + } + if (itv == 0 && ifv == 1) { + BooleanCmp.mutate(s, + op, + CondMove.getClearResult(s), + CondMove.getClearVal1(s), + CondMove.getClearVal2(s), + CondMove.getClearCond(s).flipCode(), + new OPT_BranchProfileOperand()); + return DefUseEffect.REDUCED; + } + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect floatCondMove(OPT_Instruction s) { + { + OPT_Operand val1 = CondMove.getVal1(s); + OPT_Operand val2 = CondMove.getVal2(s); + int cond = CondMove.getCond(s).evaluate(val1, val2); + if (cond != OPT_ConditionOperand.UNKNOWN) { + // BOTH CONSTANTS OR SIMILAR: FOLD + OPT_Operand val = + (cond == OPT_ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); + Move.mutate(s, FLOAT_MOVE, CondMove.getClearResult(s), val); + return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + if (val1.isConstant() && !val2.isConstant()) { + // Canonicalize by switching operands and fliping code. + OPT_Operand tmp = CondMove.getClearVal1(s); + CondMove.setVal1(s, CondMove.getClearVal2(s)); + CondMove.setVal2(s, tmp); + CondMove.getCond(s).flipOperands(); + } + OPT_Operand tv = CondMove.getTrueValue(s); + OPT_Operand fv = CondMove.getFalseValue(s); + if (tv.similar(fv)) { + Move.mutate(s, FLOAT_MOVE, CondMove.getClearResult(s), tv); + return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect doubleCondMove(OPT_Instruction s) { + { + OPT_Operand val1 = CondMove.getVal1(s); + OPT_Operand val2 = CondMove.getVal2(s); + int cond = CondMove.getCond(s).evaluate(val1, val2); + if (cond != OPT_ConditionOperand.UNKNOWN) { + // BOTH CONSTANTS OR SIMILAR: FOLD + OPT_Operand val = + (cond == OPT_ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); + Move.mutate(s, DOUBLE_MOVE, CondMove.getClearResult(s), val); + return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + if (val1.isConstant() && !val2.isConstant()) { + // Canonicalize by switching operands and fliping code. + OPT_Operand tmp = CondMove.getClearVal1(s); + CondMove.setVal1(s, CondMove.getClearVal2(s)); + CondMove.setVal2(s, tmp); + CondMove.getCond(s).flipOperands(); + } + OPT_Operand tv = CondMove.getTrueValue(s); + OPT_Operand fv = CondMove.getFalseValue(s); + if (tv.similar(fv)) { + Move.mutate(s, DOUBLE_MOVE, CondMove.getClearResult(s), tv); + return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect refCondMove(OPT_Instruction s) { + { + OPT_Operand val1 = CondMove.getVal1(s); + if (val1.isConstant()) { + OPT_Operand val2 = CondMove.getVal2(s); + if (val2.isConstant()) { + // BOTH CONSTANTS: FOLD + int cond = CondMove.getCond(s).evaluate(val1, val2); + if (cond != OPT_ConditionOperand.UNKNOWN) { + OPT_Operand val = + (cond == OPT_ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); + Move.mutate(s, REF_MOVE, CondMove.getClearResult(s), val); + return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + } else { + // Canonicalize by switching operands and fliping code. + OPT_Operand tmp = CondMove.getClearVal1(s); + CondMove.setVal1(s, CondMove.getClearVal2(s)); + CondMove.setVal2(s, tmp); + CondMove.getCond(s).flipOperands(); + } + } + if (CondMove.getTrueValue(s).similar(CondMove.getFalseValue(s))) { + OPT_Operand val = CondMove.getClearTrueValue(s); + Move.mutate(s, REF_MOVE, CondMove.getClearResult(s), val); + return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect guardCondMove(OPT_Instruction s) { + { + OPT_Operand val1 = CondMove.getVal1(s); + if (val1.isConstant()) { + OPT_Operand val2 = CondMove.getVal2(s); + if (val2.isConstant()) { + // BOTH CONSTANTS: FOLD + int cond = CondMove.getCond(s).evaluate(val1, val2); + if (cond == OPT_ConditionOperand.UNKNOWN) { + OPT_Operand val = + (cond == OPT_ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); + Move.mutate(s, GUARD_MOVE, CondMove.getClearResult(s), val); + return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + } else { + // Canonicalize by switching operands and fliping code. + OPT_Operand tmp = CondMove.getClearVal1(s); + CondMove.setVal1(s, CondMove.getClearVal2(s)); + CondMove.setVal2(s, tmp); + CondMove.getCond(s).flipOperands(); + } + } + if (CondMove.getTrueValue(s).similar(CondMove.getFalseValue(s))) { + OPT_Operand val = CondMove.getClearTrueValue(s); + Move.mutate(s, GUARD_MOVE, CondMove.getClearResult(s), val); + return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect booleanNot(OPT_Instruction s) { + if (CF_INT) { + OPT_Operand op = Unary.getVal(s); + if (op.isIntConstant()) { + // CONSTANT: FOLD + int val = op.asIntConstant().value; + if (val == 0) { + Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(1)); + } else { + Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(0)); + } + return DefUseEffect.MOVE_FOLDED; + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect booleanCmp2IntOr(OPT_Instruction s) { + if (CF_INT) { + OPT_Operand op1 = BooleanCmp2.getVal1(s); + OPT_Operand op2 = BooleanCmp2.getVal2(s); + if (op1.isConstant()) { + if (op2.isConstant()) { + // 1st 2 operands are constants, can fold if result is true + int cond1 = BooleanCmp2.getCond1(s).evaluate(op1, op2); + if (cond1 == OPT_ConditionOperand.TRUE) { + Move.mutate(s, REF_MOVE, BooleanCmp2.getResult(s), IC(1)); + return DefUseEffect.MOVE_FOLDED; + } else if (cond1 == OPT_ConditionOperand.FALSE) { + BooleanCmp.mutate(s, BOOLEAN_CMP_INT, BooleanCmp2.getResult(s), + BooleanCmp2.getVal3(s), BooleanCmp2.getVal4(s), BooleanCmp2 + .getCond2(s), BooleanCmp2.getBranchProfile2(s)); + DefUseEffect result = booleanCmpInt(s); + return (result == DefUseEffect.UNCHANGED) ? DefUseEffect.REDUCED + : result; + } + } + } + OPT_Operand op3 = BooleanCmp2.getVal3(s); + OPT_Operand op4 = BooleanCmp2.getVal4(s); + if (op3.isConstant()) { + if (op4.isConstant()) { + // 3rd and 4th operands are constants, can fold if result is true + int cond2 = BooleanCmp2.getCond1(s).evaluate(op3, op4); + if (cond2 == OPT_ConditionOperand.TRUE) { + Move.mutate(s, REF_MOVE, BooleanCmp2.getResult(s), IC(1)); + return DefUseEffect.MOVE_FOLDED; + } else if (cond2 == OPT_ConditionOperand.FALSE) { + BooleanCmp.mutate(s, BOOLEAN_CMP_INT, BooleanCmp2.getResult(s), + BooleanCmp2.getVal1(s), BooleanCmp2.getVal2(s), BooleanCmp2 + .getCond1(s), BooleanCmp2.getBranchProfile1(s)); + DefUseEffect result = booleanCmpInt(s); + return (result == DefUseEffect.UNCHANGED) ? DefUseEffect.REDUCED + : result; + } + } + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect booleanCmpInt(OPT_Instruction s) { + if (CF_INT) { + OPT_Operand op1 = BooleanCmp.getVal1(s); + OPT_Operand op2 = BooleanCmp.getVal2(s); + if (op1.isConstant()) { + if (op2.isConstant()) { + // BOTH CONSTANTS: FOLD + int cond = BooleanCmp.getCond(s).evaluate(op1, op2); + if (cond != OPT_ConditionOperand.UNKNOWN) { + Move.mutate(s, INT_MOVE, BooleanCmp.getResult(s), (cond == OPT_ConditionOperand.TRUE) ? IC(1) : IC(0)); + return DefUseEffect.MOVE_FOLDED; + } + } else { + // Canonicalize by switching operands and fliping code. + BooleanCmp.setVal1(s, op2); + BooleanCmp.setVal2(s, op1); + BooleanCmp.getCond(s).flipOperands(); + op2 = op1; + op1 = BooleanCmp.getVal1(s); + } + } + // try to fold boolean compares involving one boolean constant + // e.g.: x = (y == true) ? true : false ==> x = y + // or: x = (y == false) ? true : false ==> x = !y + if (op1.getType().isBooleanType() && op2.isConstant()) { + OPT_ConditionOperand cond = BooleanCmp.getCond(s); + int op2value = op2.asIntConstant().value; + if ((cond.isNOT_EQUAL() && (op2value == 0)) || (cond.isEQUAL() && (op2value == 1))) { + Move.mutate(s, INT_MOVE, BooleanCmp.getResult(s), op1); + return DefUseEffect.MOVE_REDUCED; + } else if ((cond.isEQUAL() && (op2value == 0)) || (cond.isNOT_EQUAL() && (op2value == 1))) { + Unary.mutate(s, BOOLEAN_NOT, BooleanCmp.getResult(s), op1); + return DefUseEffect.REDUCED; + } + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect booleanCmpAddr(OPT_Instruction s) { + if (CF_ADDR) { + OPT_Operand op1 = BooleanCmp.getVal1(s); + OPT_Operand op2 = BooleanCmp.getVal2(s); + if (op1.isConstant()) { + if (op2.isConstant()) { + // BOTH CONSTANTS: FOLD + int cond = BooleanCmp.getCond(s).evaluate(op1, op2); + if (cond != OPT_ConditionOperand.UNKNOWN) { + Move.mutate(s, REF_MOVE, BooleanCmp.getResult(s), (cond == OPT_ConditionOperand.TRUE) ? IC(1) : IC(0)); + return DefUseEffect.MOVE_FOLDED; + } + } else { + // Canonicalize by switching operands and fliping code. + OPT_Operand tmp = BooleanCmp.getClearVal1(s); + BooleanCmp.setVal1(s, BooleanCmp.getClearVal2(s)); + BooleanCmp.setVal2(s, tmp); + BooleanCmp.getCond(s).flipOperands(); + } + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect intAdd(OPT_Instruction s) { + if (CF_INT) { + canonicalizeCommutativeOperator(s); + OPT_Operand op2 = Binary.getVal2(s); + if (op2.isIntConstant()) { + int val2 = op2.asIntConstant().value; + OPT_Operand op1 = Binary.getVal1(s); + if (op1.isIntConstant()) { + // BOTH CONSTANTS: FOLD + int val1 = op1.asIntConstant().value; + Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 + val2)); + return DefUseEffect.MOVE_FOLDED; + } else { + // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS + if (val2 == 0) { + Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); + return DefUseEffect.MOVE_REDUCED; + } + } + } else { + OPT_Operand op1 = Binary.getVal1(s); + if (op1.similar(op2)) { + // Adding something to itself is the same as a multiply by 2 so + // canonicalize as a shift left + Binary.mutate(s, INT_SHL, Binary.getClearResult(s), op1, IC(1)); + return DefUseEffect.UNCHANGED; + } + } + } + return DefUseEffect.UNCHANGED; + } + + private static DefUseEffect intAnd(OPT_Instruction s) { + if (CF_INT) { + canonicalizeCommutativeOperator(s); + OPT_Operand op1 = Binary.getVal1(s); + OPT_Operand op2 = Binary.getVal2(s); + if (op1.similar(op2)) { + // THE SAME OPERAND: x & x == x + Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); + return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; + } + if (op2.isIntConstant()) { + int val2 = op2.asIntConstant().value; + if (op1.isIntConstant()) { + // BOTH CONSTANTS: FOLD + int val1 = op1.asIntConstant().value; + Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 & val2)); + return DefUseEffect.MOVE_FOLDED; + } else { + // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS + if (val2 == 0) { // x & 0 == 0 + Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); + return DefUseEffect.MOVE_FOLDED; ... [truncated message content] |
From: <mic...@us...> - 2007-08-07 09:39:58
|
Revision: 159 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=159&view=rev Author: michael_baer Date: 2007-08-07 02:40:00 -0700 (Tue, 07 Aug 2007) Log Message: ----------- Changes for most recent ARM version Modified Paths: -------------- rvmroot.patch Modified: rvmroot.patch =================================================================== --- rvmroot.patch 2007-08-06 15:25:12 UTC (rev 158) +++ rvmroot.patch 2007-08-07 09:40:00 UTC (rev 159) @@ -142,9 +142,9 @@ --- build/primordials/RVM_OPT.txt (revision 12759) +++ build/primordials/RVM_OPT.txt (working copy) @@ -16,3 +16,15 @@ - Ljava/io/FileReader; Ljava/io/PushbackReader; [Lorg/jikesrvm/compilers/opt/OPT_Simplifier$DefUseEffect; + [Lorg/jikesrvm/compilers/opt/ir/OPT_Operator; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ELF_Identity$AddressSize; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ELF_Identity$ByteOrder; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$Header$ObjectFileType; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-06 15:25:10
|
Revision: 158 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=158&view=rev Author: michael_baer Date: 2007-08-06 08:25:12 -0700 (Mon, 06 Aug 2007) Log Message: ----------- - Made optimizations by profiling optional Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/generic/decoder/CodeTranslator.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-06 15:23:44 UTC (rev 157) +++ src/org/binarytranslator/DBT_Options.java 2007-08-06 15:25:12 UTC (rev 158) @@ -93,6 +93,9 @@ /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ public static int minTraceValue = 20; + /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using profiling information.. */ + public static boolean optimizeTranslationByProfiling = false; + /** Print debug information during the translation of instructions. */ public static boolean debugTranslation = true; @@ -198,8 +201,9 @@ saveProfileToFile = value; } else if (key.equalsIgnoreCase("minTraceValue")) { minTraceValue = Integer.parseInt(value); + } else if (key.equalsIgnoreCase("optimizeTranslation")) { + optimizeTranslationByProfiling = Boolean.parseBoolean(value); } - else { throw new Error("Unknown DBT option: " + key); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-06 15:23:44 UTC (rev 157) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-06 15:25:12 UTC (rev 158) @@ -756,23 +756,31 @@ arm2ir.getCurrentBlock().insertOut(condBlock); //Query the branch profile to get the probability that this instruction is going to get executed - float skipProbability = ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); OPT_BranchProfileOperand profileOperand; - if (skipProbability == -1 || skipProbability == 0.5f) { - profileOperand = new OPT_BranchProfileOperand(); + if (DBT_Options.optimizeTranslationByProfiling) { + float skipProbability = ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); + + if (skipProbability == -1 || skipProbability == 0.5f) { + profileOperand = new OPT_BranchProfileOperand(); + } + else if (skipProbability > 0.8f) { + profileOperand = OPT_BranchProfileOperand.always(); + condBlock.setInfrequent(); + } + else if (skipProbability > 0.5f) { + profileOperand = OPT_BranchProfileOperand.likely(); + condBlock.setInfrequent(); + } + else if (skipProbability < 0.2f) { + profileOperand = OPT_BranchProfileOperand.never(); + } + else { + profileOperand = OPT_BranchProfileOperand.unlikely(); + } } - else if (skipProbability > 0.8f) { - profileOperand = OPT_BranchProfileOperand.always(); - } - else if (skipProbability > 0.5f) { - profileOperand = OPT_BranchProfileOperand.likely(); - } - else if (skipProbability < 0.2f) { - profileOperand = OPT_BranchProfileOperand.never(); - } else { - profileOperand = OPT_BranchProfileOperand.unlikely(); + profileOperand = new OPT_BranchProfileOperand(); } switch (condition) { @@ -2208,8 +2216,22 @@ //rotation = (address & 0x3) * 8 arm2ir.appendInstruction(Binary.create(INT_AND, rotation, address.copy(), new OPT_IntConstantOperand(0x3))); + + OPT_BasicBlock remainderBlock = arm2ir.createBlockAfterCurrent(); + OPT_BasicBlock rotationBlock = arm2ir.createBlockAfterCurrent(); + + //do we actually have to perform the rotation? + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), rotation.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.NOT_EQUAL(), rotationBlock.makeJumpTarget(), OPT_BranchProfileOperand.never())); + arm2ir.appendInstruction(Goto.create(GOTO, remainderBlock.makeJumpTarget())); + + //in case we are performing the rotation... + arm2ir.setCurrentBlock(rotationBlock); + rotationBlock.setInfrequent(); arm2ir.appendInstruction(Binary.create(INT_SHL, rotation.copyRO(), rotation.copy(), new OPT_IntConstantOperand(3))); arm2ir.appendRotateRight(value.copyRO(), value.copy(), rotation.copy()); + + //continue with the remainder of the instruction + arm2ir.setCurrentBlock(remainderBlock); //allow further usage of the memory address address = adrCopy; @@ -2284,6 +2306,7 @@ arm2ir.appendBranch(arm2ir.getRegister(i.Rd), lazy, BranchType.INDIRECT_BRANCH); } } + public Condition getCondition() { return i.condition; Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-06 15:23:44 UTC (rev 157) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-06 15:25:12 UTC (rev 158) @@ -158,7 +158,7 @@ /** * This variable is being set by a call to {@link #printTraceAfterCompletion()} and notifies * the system that the current trace shall be printed, after it has been completed. */ - private boolean requestPrintTrace; + private boolean printTraceAfterCompletionRequested; /** Map to locate HIR basic blocks to re-use translation within a trace */ protected final HashMap<Laziness.Key, OPT_BasicBlock> blockMap; @@ -248,7 +248,7 @@ * debug purposes. */ protected void printTraceAfterCompletion() { - requestPrintTrace = true; + printTraceAfterCompletionRequested = true; } /** This is the main loop, which generates the HIR. */ @@ -263,7 +263,10 @@ while (unresolvedDirectBranches.size() > 0 || unresolvedDynamicBranches.size() > 0) { // Resolve all open direct branches first - resolveAllDirectBranches(); + do { + resolveAllDirectBranches(); + } + while (unresolvedDirectBranches.size() > 0); // Resolve unresolved dynamic jumps resolveAllDynamicBranches(); @@ -276,14 +279,24 @@ eliminateRegisterFills(getUnusedRegisters()); } - if (requestPrintTrace) { - requestPrintTrace = false; + if (printTraceAfterCompletionRequested) { + printTraceAfterCompletionRequested = false; printNextBlocks(preFillBlock, 50); } - - // TODO: maximizeBasicBlocks() } + /* + protected final void maximizeBasicBlocks(OPT_IR ir) { + for (OPT_BasicBlock currBB = ir.cfg.firstInCodeOrder(); currBB != null;) { + if (currBB.mergeFallThrough(ir)) { + // don't advance currBB; it may have a new trivial fallthrough to + // swallow + } else { + currBB = currBB.nextBasicBlockInCodeOrder(); + } + } + }*/ + /** * Translate a sequence of instructions upto an instruction that doesn't know * its immediate/default successor. The currentBlock should be an empty basic This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-06 15:23:41
|
Revision: 157 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=157&view=rev Author: michael_baer Date: 2007-08-06 08:23:44 -0700 (Mon, 06 Aug 2007) Log Message: ----------- - changes to compile with latest RVM Modified Paths: -------------- ext/org/jikesrvm/classloader/VM_Member.java ext/org/jikesrvm/classloader/VM_Method.java ext/org/jikesrvm/compilers/common/VM_RuntimeCompiler.java ext/org/jikesrvm/compilers/opt/ia32/OPT_BURS_Helpers.java ext/org/jikesrvm/compilers/opt/ir/OPT_BC2IR.java Modified: ext/org/jikesrvm/classloader/VM_Member.java =================================================================== --- ext/org/jikesrvm/classloader/VM_Member.java 2007-08-06 14:18:07 UTC (rev 156) +++ ext/org/jikesrvm/classloader/VM_Member.java 2007-08-06 15:23:44 UTC (rev 157) @@ -1,29 +1,30 @@ /* - * This file is part of Jikes RVM (http://jikesrvm.sourceforge.net). - * The Jikes RVM project is distributed under the Common Public License (CPL). - * A copy of the license is included in the distribution, and is also - * available at http://www.opensource.org/licenses/cpl1.0.php + * This file is part of the Jikes RVM project (http://jikesrvm.org). * - * (C) Copyright IBM Corp 2001,2002 + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. */ package org.jikesrvm.classloader; -import org.jikesrvm.*; -import org.vmmagic.pragma.*; +import org.jikesrvm.VM; +import org.jikesrvm.VM_Constants; +import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Offset; /** * A field or method of a java class. - * - * @author Bowen Alpern - * @author Dave Grove - * @author Derek Lieber */ public abstract class VM_Member extends VM_AnnotatedElement implements VM_Constants, VM_ClassLoaderConstants { /** Initial value for a field offset - indicates field not laid out. */ - private static final int NO_OFFSET = Short.MIN_VALUE+1; - + private static final int NO_OFFSET = Short.MIN_VALUE + 1; + /** * The class that declared this member, avaliable by calling * getDeclaringClass once the class is loaded. @@ -54,15 +55,14 @@ /** * NOTE: Only {@link VM_Class} is allowed to create an instance of a VM_Member. - * + * * @param declaringClass the VM_TypeReference object of the class that declared this member * @param memRef the canonical memberReference for this member. * @param modifiers modifiers associated with this member. * @param signature generic type of this member * @param annotations array of runtime visible annotations */ - protected VM_Member(VM_TypeReference declaringClass, VM_MemberReference memRef, - short modifiers, VM_Atom signature, + protected VM_Member(VM_TypeReference declaringClass, VM_MemberReference memRef, short modifiers, VM_Atom signature, VM_Annotation[] annotations) { super(annotations); this.declaringClass = declaringClass; @@ -80,34 +80,34 @@ /** * Class that declared this field or method. Not available before * the class is loaded. - */ + */ @Uninterruptible public final VM_Class getDeclaringClass() { - return declaringClass.peekResolvedType().asClass(); + return declaringClass.peekType().asClass(); } /** * Canonical member reference for this member. - */ + */ @Uninterruptible - public final VM_MemberReference getMemberRef() { + public final VM_MemberReference getMemberRef() { return memRef; } /** * Name of this member. - */ + */ @Uninterruptible - public final VM_Atom getName() { + public final VM_Atom getName() { return memRef.getName(); } /** * Descriptor for this member. * something like "I" for a field or "(I)V" for a method. - */ + */ @Uninterruptible - public final VM_Atom getDescriptor() { + public final VM_Atom getDescriptor() { return memRef.getDescriptor(); } @@ -124,7 +124,7 @@ * and thus may be used to find the member by first finding the member reference. */ @Uninterruptible - public final int getId() { + public final int getId() { return memRef.getId(); } @@ -132,34 +132,34 @@ * Define hashcode in terms of VM_Atom.hashCode to enable * consistent hash codes during bootImage writing and run-time. */ - public int hashCode() { + public int hashCode() { return memRef.hashCode(); } public final String toString() { return declaringClass + "." + getName() + " " + getDescriptor(); } - + /** * Usable from classes outside its package? - */ + */ public final boolean isPublic() { - return (modifiers & ACC_PUBLIC) != 0; + return (modifiers & ACC_PUBLIC) != 0; } /** * Usable only from this class? - */ - public final boolean isPrivate() { - return (modifiers & ACC_PRIVATE) != 0; + */ + public final boolean isPrivate() { + return (modifiers & ACC_PRIVATE) != 0; } - + /** * Usable from subclasses? - */ - public final boolean isProtected() { - return (modifiers & ACC_PROTECTED) != 0; - } + */ + public final boolean isProtected() { + return (modifiers & ACC_PROTECTED) != 0; + } /** * Get the member's modifiers. @@ -167,10 +167,10 @@ public final int getModifiers() { return modifiers; } - + /** * Has the field been laid out in the object yet ? - * + * * @return */ public final boolean hasOffset() { @@ -179,7 +179,7 @@ //------------------------------------------------------------------// // Section 2. // - // The following are available after the declaring class has been // + // The following are available after the declaring class has been // // "resolved". // //------------------------------------------------------------------// @@ -191,10 +191,10 @@ * <li> For a non-static field: offset of field from start of object * <li> For a non-static method: offset of code object reference from start of tib * </ul> - */ + */ @Uninterruptible - public final Offset getOffset() { - if (VM.VerifyAssertions) VM._assert(declaringClass.isResolved()); + public final Offset getOffset() { + if (VM.VerifyAssertions) VM._assert(declaringClass.isLoaded()); if (VM.VerifyAssertions) VM._assert(offset != NO_OFFSET); return Offset.fromIntSignExtend(offset); } Modified: ext/org/jikesrvm/classloader/VM_Method.java =================================================================== --- ext/org/jikesrvm/classloader/VM_Method.java 2007-08-06 14:18:07 UTC (rev 156) +++ ext/org/jikesrvm/classloader/VM_Method.java 2007-08-06 15:23:44 UTC (rev 157) @@ -1,121 +1,96 @@ /* - * This file is part of Jikes RVM (http://jikesrvm.sourceforge.net). - * The Jikes RVM project is distributed under the Common Public License (CPL). - * A copy of the license is included in the distribution, and is also - * available at http://www.opensource.org/licenses/cpl1.0.php + * This file is part of the Jikes RVM project (http://jikesrvm.org). * - * (C) Copyright IBM Corp 2001,2002 + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. */ package org.jikesrvm.classloader; -import org.jikesrvm.*; +import java.io.DataInputStream; +import java.io.IOException; import org.jikesrvm.ArchitectureSpecific.VM_CodeArray; import org.jikesrvm.ArchitectureSpecific.VM_LazyCompilationTrampolineGenerator; +import org.jikesrvm.VM; import org.jikesrvm.compilers.common.VM_CompiledMethod; import org.jikesrvm.compilers.common.VM_CompiledMethods; -import org.jikesrvm.runtime.VM_Statics; import org.jikesrvm.runtime.VM_Entrypoints; - -import java.io.DataInputStream; -import java.io.IOException; - +import org.jikesrvm.runtime.VM_Statics; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Unpreemptible; import org.vmmagic.unboxed.Offset; -import org.vmmagic.pragma.*; /** - * A method of a java class corresponding to a method_info structure in the - * class file. A method is read from a class file using the {@link #readMethod} - * method. - * - * @author Bowen Alpern - * @author Dave Grove - * @author Derek Lieber - * @author Ian Rogers + * A method of a java class corresponding to a method_info structure + * in the class file. A method is read from a class file using the + * {@link #readMethod} method. */ -public abstract class VM_Method extends VM_Member implements - VM_BytecodeConstants { +public abstract class VM_Method extends VM_Member implements VM_BytecodeConstants { /** * current compiled method for this method */ protected VM_CompiledMethod currentCompiledMethod; - /** * exceptions this method might throw (null --> none) */ protected final VM_TypeReference[] exceptionTypes; - /** - * Method paramter annotations from the class file that are described as - * runtime visible. These annotations are available to the reflection API. + * Method paramter annotations from the class file that are + * described as runtime visible. These annotations are available to + * the reflection API. */ protected final VM_Annotation[] parameterAnnotations; - /** * A value present in the method info tables of annotation types. It * represents the default result from an annotation method. */ protected final Object annotationDefault; - /** - * The offset of this virtual method in the jtoc if it's been placed there by - * constant propagation, otherwise 0. + * The offset of this virtual method in the jtoc if it's been placed + * there by constant propagation, otherwise 0. */ private Offset jtocOffset; /** * Construct a read method - * - * @param declaringClass - * the VM_Class object of the class that declared this field - * @param memRef - * the canonical memberReference for this method. - * @param modifiers - * modifiers associated with this method. - * @param exceptionTypes - * exceptions thrown by this method. - * @param signature - * generic type of this method. - * @param annotations - * array of runtime visible annotations - * @param parameterAnnotations - * array of runtime visible parameter annotations - * @param annotationDefault - * value for this annotation that appears + * + * @param declaringClass the VM_Class object of the class that declared this field + * @param memRef the canonical memberReference for this method. + * @param modifiers modifiers associated with this method. + * @param exceptionTypes exceptions thrown by this method. + * @param signature generic type of this method. + * @param annotations array of runtime visible annotations + * @param parameterAnnotations array of runtime visible parameter annotations + * @param annotationDefault value for this annotation that appears */ - protected VM_Method(VM_TypeReference declaringClass, - VM_MemberReference memRef, short modifiers, - VM_TypeReference[] exceptionTypes, VM_Atom signature, - VM_Annotation[] annotations, VM_Annotation[] parameterAnnotations, - Object annotationDefault) { - super(declaringClass, memRef, (short) (modifiers & APPLICABLE_TO_METHODS), - signature, annotations); + protected VM_Method(VM_TypeReference declaringClass, VM_MemberReference memRef, short modifiers, + VM_TypeReference[] exceptionTypes, VM_Atom signature, VM_Annotation[] annotations, + VM_Annotation[] parameterAnnotations, Object annotationDefault) { + super(declaringClass, memRef, (short) (modifiers & APPLICABLE_TO_METHODS), signature, annotations); this.parameterAnnotations = parameterAnnotations; this.annotationDefault = annotationDefault; - memRef.asMethodReference().setResolvedMember(this); this.exceptionTypes = exceptionTypes; this.jtocOffset = Offset.fromIntSignExtend(-1); } /** - * Called from {@link VM_Class#readClass(VM_TypeReference, DataInputStream)} - * to create an instance of a VM_Method by reading the relevant data from the - * argument bytecode stream. - * - * @param declaringClass - * the VM_TypeReference of the class being loaded - * @param constantPool - * the constantPool of the VM_Class object that's being constructed - * @param memRef - * the canonical memberReference for this member. - * @param modifiers - * modifiers associated with this member. - * @param input - * the DataInputStream to read the method's attributes from + * Called from {@link VM_Class#readClass(VM_TypeReference,DataInputStream)} to create an + * instance of a VM_Method by reading the relevant data from the argument bytecode stream. + * + * @param declaringClass the VM_TypeReference of the class being loaded + * @param constantPool the constantPool of the VM_Class object that's being constructed + * @param memRef the canonical memberReference for this member. + * @param modifiers modifiers associated with this member. + * @param input the DataInputStream to read the method's attributes from */ - static VM_Method readMethod(VM_TypeReference declaringClass, - int[] constantPool, VM_MemberReference memRef, short modifiers, - DataInputStream input) throws IOException { + static VM_Method readMethod(VM_TypeReference declaringClass, int[] constantPool, VM_MemberReference memRef, + short modifiers, DataInputStream input) throws IOException { short tmp_localWords = 0; short tmp_operandWords = 0; byte[] tmp_bytecodes = null; @@ -129,8 +104,7 @@ // Read the attributes for (int i = 0, n = input.readUnsignedShort(); i < n; i++) { - VM_Atom attName = VM_Class - .getUtf(constantPool, input.readUnsignedShort()); + VM_Atom attName = VM_Class.getUtf(constantPool, input.readUnsignedShort()); int attLength = input.readInt(); // Only bother to interpret non-boring Method attributes @@ -139,8 +113,7 @@ tmp_localWords = input.readShort(); tmp_bytecodes = new byte[input.readInt()]; input.readFully(tmp_bytecodes); - tmp_exceptionHandlerMap = VM_ExceptionHandlerMap - .readExceptionHandlerMap(input, constantPool); + tmp_exceptionHandlerMap = VM_ExceptionHandlerMap.readExceptionHandlerMap(input, constantPool); // Read the attributes portion of the code attribute for (int j = 0, n2 = input.readUnsignedShort(); j < n2; j++) { @@ -158,8 +131,7 @@ } } } else { - // All other entries in the attribute portion of the code attribute - // are boring. + // All other entries in the attribute portion of the code attribute are boring. input.skipBytes(attLength); } } @@ -168,25 +140,21 @@ if (cnt != 0) { tmp_exceptionTypes = new VM_TypeReference[cnt]; for (int j = 0, m = tmp_exceptionTypes.length; j < m; ++j) { - tmp_exceptionTypes[j] = VM_Class.getTypeRef(constantPool, input - .readUnsignedShort()); + tmp_exceptionTypes[j] = VM_Class.getTypeRef(constantPool, input.readUnsignedShort()); } } } else if (attName == VM_ClassLoader.syntheticAttributeName) { modifiers |= ACC_SYNTHETIC; } else if (attName == VM_ClassLoader.signatureAttributeName) { - tmp_signature = VM_Class - .getUtf(constantPool, input.readUnsignedShort()); + tmp_signature = VM_Class.getUtf(constantPool, input.readUnsignedShort()); } else if (attName == VM_ClassLoader.runtimeVisibleAnnotationsAttributeName) { - annotations = VM_AnnotatedElement.readAnnotations(constantPool, input, - 2, declaringClass.getClassLoader()); + annotations = VM_AnnotatedElement.readAnnotations(constantPool, input, 2, declaringClass.getClassLoader()); } else if (attName == VM_ClassLoader.runtimeVisibleParameterAnnotationsAttributeName) { - parameterAnnotations = VM_AnnotatedElement.readAnnotations( - constantPool, input, 1, declaringClass.getClassLoader()); + parameterAnnotations = + VM_AnnotatedElement.readAnnotations(constantPool, input, 1, declaringClass.getClassLoader()); } else if (attName == VM_ClassLoader.annotationDefaultAttributeName) { try { - tmp_annotationDefault = VM_Annotation.readValue(constantPool, input, - declaringClass.getClassLoader()); + tmp_annotationDefault = VM_Annotation.readValue(constantPool, input, declaringClass.getClassLoader()); } catch (ClassNotFoundException e) { throw new Error(e); } @@ -197,73 +165,100 @@ } VM_Method method; if ((modifiers & ACC_NATIVE) != 0) { - method = new VM_NativeMethod(declaringClass, memRef, modifiers, - tmp_exceptionTypes, tmp_signature, annotations, parameterAnnotations, - tmp_annotationDefault); + method = + new VM_NativeMethod(declaringClass, + memRef, + modifiers, + tmp_exceptionTypes, + tmp_signature, + annotations, + parameterAnnotations, + tmp_annotationDefault); } else if ((modifiers & ACC_ABSTRACT) != 0) { - method = new VM_AbstractMethod(declaringClass, memRef, modifiers, - tmp_exceptionTypes, tmp_signature, annotations, parameterAnnotations, - tmp_annotationDefault); + method = + new VM_AbstractMethod(declaringClass, + memRef, + modifiers, + tmp_exceptionTypes, + tmp_signature, + annotations, + parameterAnnotations, + tmp_annotationDefault); } else { - method = new VM_NormalMethod(declaringClass, memRef, modifiers, - tmp_exceptionTypes, tmp_localWords, tmp_operandWords, tmp_bytecodes, - tmp_exceptionHandlerMap, tmp_lineNumberMap, constantPool, - tmp_signature, annotations, parameterAnnotations, - tmp_annotationDefault); + method = + new VM_NormalMethod(declaringClass, + memRef, + modifiers, + tmp_exceptionTypes, + tmp_localWords, + tmp_operandWords, + tmp_bytecodes, + tmp_exceptionHandlerMap, + tmp_lineNumberMap, + constantPool, + tmp_signature, + annotations, + parameterAnnotations, + tmp_annotationDefault); } return method; } /** - * Create a copy of the method that occurs in the annotation interface. The - * method body will contain a read of the field at the constant pool index - * specified. - * - * @param annotationClass - * the class this method belongs to - * @param constantPool - * for the class - * @param memRef - * the member reference corresponding to this method - * @param interfaceMethod - * the interface method that will copied to produce the annotation - * method - * @param constantPoolIndex - * the index of the field that will be returned by this method + * Create a copy of the method that occurs in the annotation + * interface. The method body will contain a read of the field at + * the constant pool index specified. + * + * @param annotationClass the class this method belongs to + * @param constantPool for the class + * @param memRef the member reference corresponding to this method + * @param interfaceMethod the interface method that will copied to + * produce the annotation method + * @param constantPoolIndex the index of the field that will be + * returned by this method * @return the created method */ - static VM_Method createAnnotationMethod(VM_TypeReference annotationClass, - int[] constantPool, VM_MemberReference memRef, VM_Method interfaceMethod, - int constantPoolIndex) { - byte[] bytecodes = new byte[] { (byte) JBC_aload_0, (byte) JBC_getfield, - (byte) (constantPoolIndex >>> 8), (byte) constantPoolIndex, + static VM_Method createAnnotationMethod(VM_TypeReference annotationClass, int[] constantPool, + VM_MemberReference memRef, VM_Method interfaceMethod, + int constantPoolIndex) { + byte[] bytecodes = + new byte[]{ + (byte) JBC_aload_0, + (byte) JBC_getfield, (byte) (constantPoolIndex >>> 8), (byte) constantPoolIndex, // Xreturn - (byte) typeRefToReturnBytecode(interfaceMethod.getReturnType()) }; - return new VM_NormalMethod(annotationClass, memRef, (short) (ACC_PUBLIC - | ACC_FINAL | ACC_SYNTHETIC), null, (short) 1, (short) 2, bytecodes, - null, null, constantPool, null, null, null, null); + (byte) typeRefToReturnBytecode(interfaceMethod.getReturnType())}; + return new VM_NormalMethod(annotationClass, + memRef, + (short) (ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC), + null, + (short) 1, + (short) 2, + bytecodes, + null, + null, + constantPool, + null, + null, + null, + null); } /** * Create a method to initialise the annotation class - * - * @param aClass - * the class this method belongs to - * @param constantPool - * for the class - * @param memRef - * the member reference corresponding to this method - * @param objectInitIndex - * an index into the constant pool for a method reference to - * java.lang.Object.<init> + * + * @param aClass the class this method belongs to + * @param constantPool for the class + * @param memRef the member reference corresponding to this method + * @param objectInitIndex an index into the constant pool for a + * method reference to java.lang.Object.<init> * @param aFields * @param aMethods * @return the created method */ - static VM_Method createAnnotationInit(VM_TypeReference aClass, - int[] constantPool, VM_MemberReference memRef, int objectInitIndex, - VM_Field[] aFields, VM_Method[] aMethods, int[] defaultConstants) { + static VM_Method createAnnotationInit(VM_TypeReference aClass, int[] constantPool, VM_MemberReference memRef, + int objectInitIndex, VM_Field[] aFields, VM_Method[] aMethods, + int[] defaultConstants) { byte[] bytecode = new byte[6 + (defaultConstants.length * 7)]; bytecode[0] = (byte) JBC_aload_0; // stack[0] = this bytecode[1] = (byte) JBC_aload_1; // stack[1] = instanceof VM_Annotation @@ -272,7 +267,7 @@ bytecode[4] = (byte) objectInitIndex; for (int i = 0, j = 0; i < aMethods.length; i++) { if (aMethods[i].annotationDefault != null) { - bytecode[(j * 7) + 5 + 0] = (byte) JBC_aload_0; // stack[0] = this + bytecode[(j * 7) + 5 + 0] = (byte) JBC_aload_0; // stack[0] = this if (VM_Class.getLiteralSize(constantPool, defaultConstants[j]) == BYTES_IN_INT) { bytecode[(j * 7) + 5 + 1] = (byte) JBC_ldc_w; // stack[1] = value } else { @@ -287,22 +282,36 @@ } } bytecode[bytecode.length - 1] = (byte) JBC_return; - return new VM_NormalMethod(aClass, memRef, - (short) (ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC), null, (short) 2, - (short) 3, bytecode, null, null, constantPool, null, null, null, null); + return new VM_NormalMethod(aClass, + memRef, + (short) (ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC), + null, + (short) 2, + (short) 3, + bytecode, + null, + null, + constantPool, + null, + null, + null, + null); } /** - * What would be the appropriate return bytecode for the given type reference? + * What would be the appropriate return bytecode for the given type + * reference? */ private static int typeRefToReturnBytecode(VM_TypeReference tr) { if (!tr.isPrimitiveType()) { return JBC_areturn; } else { - VM_Primitive pt = (VM_Primitive) tr.peekResolvedType(); - if ((pt == VM_Type.BooleanType) || (pt == VM_Type.ByteType) - || (pt == VM_Type.ShortType) || (pt == VM_Type.CharType) - || (pt == VM_Type.IntType)) { + VM_Primitive pt = (VM_Primitive) tr.peekType(); + if ((pt == VM_Type.BooleanType) || + (pt == VM_Type.ByteType) || + (pt == VM_Type.ShortType) || + (pt == VM_Type.CharType) || + (pt == VM_Type.IntType)) { return JBC_ireturn; } else if (pt == VM_Type.LongType) { return JBC_lreturn; @@ -350,8 +359,8 @@ } /** - * Type of this method's parameters. Note: does *not* include implicit "this" - * parameter, if any. + * Type of this method's parameters. + * Note: does *not* include implicit "this" parameter, if any. */ @Uninterruptible public final VM_TypeReference[] getParameterTypes() { @@ -359,8 +368,8 @@ } /** - * Space required by this method for its parameters, in words. Note: does - * *not* include implicit "this" parameter, if any. + * Space required by this method for its parameters, in words. + * Note: does *not* include implicit "this" parameter, if any. */ @Uninterruptible public final int getParameterWords() { @@ -375,12 +384,11 @@ } /** - * Get the current compiled method for this method. Will return null if there - * is no current compiled method! - * - * We make this method Unpreemptible to avoid a race-condition in - * VM_Reflection.invoke. - * + * Get the current compiled method for this method. + * Will return null if there is no current compiled method! + * + * We make this method Unpreemptible to avoid a race-condition + * in VM_Reflection.invoke. * @return compiled method */ @Unpreemptible @@ -424,8 +432,7 @@ * Not implemented in Java and use C not JNI calling convention */ public final boolean isSysCall() { - return isNative() && isStatic() - && isAnnotationDeclared(VM_TypeReference.SysCall); + return isNative() && isStatic() && isAnnotationDeclared(VM_TypeReference.SysCall); } /** @@ -444,9 +451,8 @@ } /** - * Exceptions thrown by this method - something like { - * "java/lang/IOException", "java/lang/EOFException" } - * + * Exceptions thrown by this method - + * something like { "java/lang/IOException", "java/lang/EOFException" } * @return info (null --> method doesn't throw any exceptions) */ @Uninterruptible @@ -455,47 +461,36 @@ } /** - * Is this method interruptible? In other words, should the compiler insert - * yieldpoints in method prologue, epilogue, and backwards branches. Also, - * only methods that are Interruptible have stackoverflow checks in the method - * prologue (since there is no mechanism for handling a stackoverflow that - * doesn't violate the uninterruptiblity of the method). To determine if a - * method is interruptible, the following conditions are checked (<em>in order</em>): + * Is this method interruptible? + * In other words, should the compiler insert yieldpoints + * in method prologue, epilogue, and backwards branches. + * Also, only methods that are Interruptible have stackoverflow checks + * in the method prologue (since there is no mechanism for handling a stackoverflow + * that doesn't violate the uninterruptiblity of the method). + * To determine if a method is interruptible, the following conditions + * are checked (<em>in order</em>): * <ul> * <li> If it is a <clinit> or <init> method then it is interruptible. - * <li> If is the synthetic 'this' method used by jikes to factor out default - * initializers for <init> methods then it is interruptible. - * <li> If it is annotated with <CODE>Interruptible</CODE> it is - * interruptible. - * <li> If it is annotated with <CODE>Preemptible</CODE> it is - * interruptible. - * <li> If it is annotated with <CODE>Uninterruptible</CODE> it is not - * interruptible. - * <li> If it is annotated with <CODE>UninterruptibleNoWarn</CODE> it is not - * interruptible. - * <li> If it is annotated with <CODE>Unpreemptible</CODE> it is not - * interruptible. + * <li> If is the synthetic 'this' method used by jikes to + * factor out default initializers for <init> methods then it is interruptible. + * <li> If it is annotated with <CODE>Interruptible</CODE> it is interruptible. + * <li> If it is annotated with <CODE>Preemptible</CODE> it is interruptible. + * <li> If it is annotated with <CODE>Uninterruptible</CODE> it is not interruptible. + * <li> If it is annotated with <CODE>UninterruptibleNoWarn</CODE> it is not interruptible. + * <li> If it is annotated with <CODE>Unpreemptible</CODE> it is not interruptible. * <li> If its declaring class is annotated with <CODE>Uninterruptible</CODE> - * or <CODE>Unpreemptible</CODE> it is not interruptible. + * or <CODE>Unpreemptible</CODE> it is not interruptible. * </ul> */ public final boolean isInterruptible() { - if (isClassInitializer() || isObjectInitializer()) - return true; - if (isObjectInitializerHelper()) - return true; - if (hasInterruptibleAnnotation()) - return true; - if (hasPreemptibleAnnotation()) - return true; - if (hasUninterruptibleNoWarnAnnotation()) - return false; - if (hasUninterruptibleAnnotation()) - return false; - if (hasUnpreemptibleAnnotation()) - return false; - if (getDeclaringClass().hasUnpreemptibleAnnotation()) - return false; + if (isClassInitializer() || isObjectInitializer()) return true; + if (isObjectInitializerHelper()) return true; + if (hasInterruptibleAnnotation()) return true; + if (hasPreemptibleAnnotation()) return true; + if (hasUninterruptibleNoWarnAnnotation()) return false; + if (hasUninterruptibleAnnotation()) return false; + if (hasUnpreemptibleAnnotation()) return false; + if (getDeclaringClass().hasUnpreemptibleAnnotation()) return false; return !getDeclaringClass().hasUninterruptibleAnnotation(); } @@ -503,20 +498,13 @@ * Is the method Unpreemptible? See the comment in {@link #isInterruptible} */ public final boolean isUnpreemptible() { - if (isClassInitializer() || isObjectInitializer()) - return false; - if (isObjectInitializerHelper()) - return false; - if (hasInterruptibleAnnotation()) - return false; - if (hasPreemptibleAnnotation()) - return false; - if (hasUninterruptibleAnnotation()) - return false; - if (hasUninterruptibleNoWarnAnnotation()) - return false; - if (hasUnpreemptibleAnnotation()) - return true; + if (isClassInitializer() || isObjectInitializer()) return false; + if (isObjectInitializerHelper()) return false; + if (hasInterruptibleAnnotation()) return false; + if (hasPreemptibleAnnotation()) return false; + if (hasUninterruptibleAnnotation()) return false; + if (hasUninterruptibleNoWarnAnnotation()) return false; + if (hasUnpreemptibleAnnotation()) return true; return getDeclaringClass().hasUnpreemptibleAnnotation(); } @@ -524,28 +512,30 @@ * Is the method Uninterruptible? See the comment in {@link #isInterruptible} */ public final boolean isUninterruptible() { - if (isClassInitializer() || isObjectInitializer()) - return false; - if (isObjectInitializerHelper()) - return false; - if (hasInterruptibleAnnotation()) - return false; - if (hasPreemptibleAnnotation()) - return false; - if (hasUnpreemptibleAnnotation()) - return false; - if (hasUninterruptibleAnnotation()) - return true; - if (hasUninterruptibleNoWarnAnnotation()) - return true; + if (isClassInitializer() || isObjectInitializer()) return false; + if (isObjectInitializerHelper()) return false; + if (hasInterruptibleAnnotation()) return false; + if (hasPreemptibleAnnotation()) return false; + if (hasUnpreemptibleAnnotation()) return false; + if (hasUninterruptibleAnnotation()) return true; + if (hasUninterruptibleNoWarnAnnotation()) return true; return getDeclaringClass().hasUninterruptibleAnnotation(); } /** - * Has this method been marked as forbidden to inline? ie., it is marked with - * the <CODE>NoInline</CODE> annotation or the <CODE>NoOptCompile</CODE> - * annotation? + * Is the method Pure? That is would it, without any side effects, return the + * same value given the same arguments? + * + * @return whether the method has a pure annotation */ + public final boolean isPure() { + return hasPureAnnotation(); + } + /** + * Has this method been marked as forbidden to inline? + * ie., it is marked with the <CODE>NoInline</CODE> annotation or + * the <CODE>NoOptCompile</CODE> annotation? + */ public final boolean hasNoInlinePragma() { return (hasNoInlineAnnotation() || hasNoOptCompileAnnotation()); } @@ -554,57 +544,48 @@ * @return true if the method may write to a given field */ public boolean mayWrite(VM_Field field) { - return true; // be conservative. native methods can write to anything + return true; // be conservative. native methods can write to anything } /** - * @return true if the method is the implementation of a runtime service that - * is called "under the covers" from the generated code and thus is - * not subject to inlining via the normal mechanisms. + * @return true if the method is the implementation of a runtime service + * that is called "under the covers" from the generated code and thus is not subject to + * inlining via the normal mechanisms. */ public boolean isRuntimeServiceMethod() { - return false; // only VM_NormalMethods can be runtime service impls in Jikes - // RVM and they override this method + return false; // only VM_NormalMethods can be runtime service impls in Jikes RVM and they override this method } - // ------------------------------------------------------------------// - // Section 2. // - // The following are available after the declaring class has been // - // "resolved". // - // ------------------------------------------------------------------// + //------------------------------------------------------------------// + // Section 2. // + // The following are available after the declaring class has been // + // "resolved". // + //------------------------------------------------------------------// /** - * Get the code array that corresponds to the entry point (prologue) for the - * method. + * Get the code array that corresponds to the entry point (prologue) for the method. */ public final synchronized VM_CodeArray getCurrentEntryCodeArray() { VM_Class declaringClass = getDeclaringClass(); - if (VM.VerifyAssertions) - VM._assert(declaringClass.isResolved()); + if (VM.VerifyAssertions) VM._assert(declaringClass.isResolved()); if (isCompiled()) { return currentCompiledMethod.getEntryCodeArray(); } else if (!VM.writingBootImage || isNative()) { if (!isStatic() && !isObjectInitializer() && !isPrivate()) { // A non-private virtual method. - if (declaringClass.isJavaLangObjectType() - || declaringClass.getSuperClass().findVirtualMethod(getName(), - getDescriptor()) == null) { - // The root method of a virtual method family can use the lazy method - // invoker directly. - return VM_Entrypoints.lazyMethodInvokerMethod - .getCurrentEntryCodeArray(); + if (declaringClass.isJavaLangObjectType() || + declaringClass.getSuperClass().findVirtualMethod(getName(), getDescriptor()) == null) { + // The root method of a virtual method family can use the lazy method invoker directly. + return VM_Entrypoints.lazyMethodInvokerMethod.getCurrentEntryCodeArray(); } else { - // All other virtual methods in the family must generate unique stubs - // to - // ensure correct operation of the method test (guarded inlining of - // virtual calls). + // All other virtual methods in the family must generate unique stubs to + // ensure correct operation of the method test (guarded inlining of virtual calls). return VM_LazyCompilationTrampolineGenerator.getTrampoline(); } } else { // We'll never do a method test against this method. // Therefore we can use the lazy method invoker directly. - return VM_Entrypoints.lazyMethodInvokerMethod - .getCurrentEntryCodeArray(); + return VM_Entrypoints.lazyMethodInvokerMethod.getCurrentEntryCodeArray(); } } else { compile(); @@ -613,17 +594,15 @@ } /** - * Generate machine code for this method if valid machine code doesn't already - * exist. Return the resulting VM_CompiledMethod object. + * Generate machine code for this method if valid + * machine code doesn't already exist. + * Return the resulting VM_CompiledMethod object. */ public final synchronized void compile() { - if (VM.VerifyAssertions) - VM._assert(getDeclaringClass().isResolved()); - if (isCompiled()) - return; + if (VM.VerifyAssertions) VM._assert(getDeclaringClass().isResolved()); + if (isCompiled()) return; - if (VM.TraceClassLoading && VM.runningVM) - VM.sysWrite("VM_Method: (begin) compiling " + this + "\n"); + if (VM.TraceClassLoading && VM.runningVM) VM.sysWrite("VM_Method: (begin) compiling " + this + "\n"); VM_CompiledMethod cm = genCode(); @@ -636,37 +615,31 @@ } } - if (VM.TraceClassLoading && VM.runningVM) - VM.sysWrite("VM_Method: (end) compiling " + this + "\n"); + if (VM.TraceClassLoading && VM.runningVM) VM.sysWrite("VM_Method: (end) compiling " + this + "\n"); } protected abstract VM_CompiledMethod genCode(); - // ----------------------------------------------------------------// - // Section 3. // + //----------------------------------------------------------------// + // Section 3. // // The following are available after the declaring class has been // - // "instantiated". // - // ----------------------------------------------------------------// + // "instantiated". // + //----------------------------------------------------------------// /** * Change machine code that will be used by future executions of this method * (ie. optimized <-> non-optimized) - * - * @param compiledMethod - * new machine code Side effect: updates jtoc or method dispatch - * tables ("type information blocks") for this class and its - * subclasses + * @param compiledMethod new machine code + * Side effect: updates jtoc or method dispatch tables + * ("type information blocks") + * for this class and its subclasses */ - public synchronized void replaceCompiledMethod( - VM_CompiledMethod compiledMethod) { - if (VM.VerifyAssertions) - VM._assert(getDeclaringClass().isInstantiated()); - // If we're replacing with a non-null compiledMethod, ensure that is still - // valid! + public synchronized void replaceCompiledMethod(VM_CompiledMethod compiledMethod) { + if (VM.VerifyAssertions) VM._assert(getDeclaringClass().isInstantiated()); + // If we're replacing with a non-null compiledMethod, ensure that is still valid! if (compiledMethod != null) { synchronized (compiledMethod) { - if (compiledMethod.isInvalid()) - return; + if (compiledMethod.isInvalid()) return; } } @@ -693,8 +666,7 @@ * If CM is the current compiled code for this, then invaldiate it. */ public final synchronized void invalidateCompiledMethod(VM_CompiledMethod cm) { - if (VM.VerifyAssertions) - VM._assert(getDeclaringClass().isInstantiated()); + if (VM.VerifyAssertions) VM._assert(getDeclaringClass().isInstantiated()); if (currentCompiledMethod == cm) { replaceCompiledMethod(null); } @@ -704,8 +676,7 @@ * Find or create a jtoc offset for this method */ public final synchronized Offset findOrCreateJtocOffset() { - if (VM.VerifyAssertions) - VM._assert(!isStatic() && !isObjectInitializer()); + if (VM.VerifyAssertions) VM._assert(!isStatic() && !isObjectInitializer()); if (jtocOffset.EQ(Offset.zero())) { jtocOffset = VM_Statics.allocateReferenceSlot(); VM_Statics.setSlotContents(jtocOffset, getCurrentEntryCodeArray()); Modified: ext/org/jikesrvm/compilers/common/VM_RuntimeCompiler.java =================================================================== --- ext/org/jikesrvm/compilers/common/VM_RuntimeCompiler.java 2007-08-06 14:18:07 UTC (rev 156) +++ ext/org/jikesrvm/compilers/common/VM_RuntimeCompiler.java 2007-08-06 15:23:44 UTC (rev 157) @@ -1,85 +1,97 @@ /* - * This file is part of Jikes RVM (http://jikesrvm.sourceforge.net). - * The Jikes RVM project is distributed under the Common Public License (CPL). - * A copy of the license is included in the distribution, and is also - * available at http://www.opensource.org/licenses/cpl1.0.php + * This file is part of the Jikes RVM project (http://jikesrvm.org). * - * (C) Copyright IBM Corp. 2001, 2005 + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. */ package org.jikesrvm.compilers.common; -import org.jikesrvm.*; -import org.jikesrvm.classloader.*; -import org.jikesrvm.compilers.baseline.*; -import org.jikesrvm.compilers.opt.*; +import org.jikesrvm.ArchitectureSpecific; +import org.jikesrvm.ArchitectureSpecific.VM_JNICompiler; +import org.jikesrvm.VM; +import org.jikesrvm.VM_Callbacks; +import org.jikesrvm.VM_Constants; import org.jikesrvm.adaptive.controller.VM_Controller; import org.jikesrvm.adaptive.controller.VM_ControllerMemory; import org.jikesrvm.adaptive.controller.VM_ControllerPlan; import org.jikesrvm.adaptive.recompilation.VM_InvocationCounts; import org.jikesrvm.adaptive.recompilation.VM_PreCompile; import org.jikesrvm.adaptive.recompilation.instrumentation.VM_AOSInstrumentationPlan; -import org.jikesrvm.adaptive.util.*; -import org.jikesrvm.ArchitectureSpecific.VM_JNICompiler; +import org.jikesrvm.adaptive.util.VM_AOSGenerator; +import org.jikesrvm.adaptive.util.VM_AOSLogging; +import org.jikesrvm.adaptive.util.VM_CompilerAdviceAttribute; +import org.jikesrvm.classloader.VM_NativeMethod; +import org.jikesrvm.classloader.VM_NormalMethod; +import org.jikesrvm.classloader.VM_Type; +import org.jikesrvm.classloader.VM_TypeReference; +import org.jikesrvm.compilers.baseline.VM_BaselineCompiler; +import org.jikesrvm.compilers.opt.OPT_CompilationPlan; +import org.jikesrvm.compilers.opt.OPT_Compiler; +import org.jikesrvm.compilers.opt.OPT_MagicNotImplementedException; +import org.jikesrvm.compilers.opt.OPT_OptimizationPlanElement; +import org.jikesrvm.compilers.opt.OPT_OptimizationPlanner; +import org.jikesrvm.compilers.opt.OPT_OptimizingCompilerException; +import org.jikesrvm.compilers.opt.OPT_Options; import org.jikesrvm.runtime.VM_Time; -import org.jikesrvm.scheduler.VM_Thread; +import org.jikesrvm.scheduler.VM_Scheduler; /** - * Harness to select which compiler to dynamically compile a method in first - * invocation. - * - * A place to put code common to all runtime compilers. This includes - * instrumentation code to get equivalent data for each of the runtime - * compilers. + * Harness to select which compiler to dynamically + * compile a method in first invocation. + * + * A place to put code common to all runtime compilers. + * This includes instrumentation code to get equivalent data for + * each of the runtime compilers. * <p> * We collect the following data for each compiler * <ol> - * <li> total number of methods complied by the compiler - * <li> total compilation time in milliseconds. - * <li> total number of bytes of bytecodes compiled by the compiler (under the - * assumption that there is no padding in the bytecode array and thus - * VM_Method.getBytecodes().length is the number bytes of bytecode for a method) - * <li> total number of machine code insructions generated by the compiler - * (under the assumption that there is no (excessive) padding in the machine - * code array and thus VM_CompiledMethod.numberOfInsturctions() is a close - * enough approximation of the number of machinecodes generated) + * <li> + * total number of methods complied by the compiler + * <li> + * total compilation time in milliseconds. + * <li> + * total number of bytes of bytecodes compiled by the compiler + * (under the assumption that there is no padding in the bytecode + * array and thus VM_Method.getBytecodes().length is the number bytes + * of bytecode for a method) + * <li> + * total number of machine code insructions generated by the compiler + * (under the assumption that there is no (excessive) padding in the + * machine code array and thus VM_CompiledMethod.numberOfInsturctions() + * is a close enough approximation of the number of machinecodes generated) * </ol> - * Note that even if 3. & 4. are inflated due to padding, the numbers will still - * be an accurate measure of the space costs of the compile-only approach. - * - * @author Matthew Arnold - * @author Dave Grove - * @author Michael Hind + * Note that even if 3. & 4. are inflated due to padding, the numbers will + * still be an accurate measure of the space costs of the compile-only + * approach. */ -public class VM_RuntimeCompiler implements VM_Constants, - VM_Callbacks.ExitMonitor { +public class VM_RuntimeCompiler implements VM_Constants, VM_Callbacks.ExitMonitor { // Use these to encode the compiler for record() public static final byte JNI_COMPILER = 0; - public static final byte BASELINE_COMPILER = 1; - public static final byte OPT_COMPILER = 2; // Data accumulators - private static final String[] name = { "JNI\t", "Base\t", "Opt\t" }; // Output - // names + private static final String[] name = {"JNI\t", "Base\t", "Opt\t"}; // Output names + private static int[] totalMethods = {0, 0, 0}; + private static double[] totalCompTime = {0, 0, 0}; + private static int[] totalBCLength = {0, 0, 0}; + private static int[] totalMCLength = {0, 0, 0}; - private static int[] totalMethods = { 0, 0, 0 }; - - private static double[] totalCompTime = { 0, 0, 0 }; - - private static int[] totalBCLength = { 0, 0, 0 }; - - private static int[] totalMCLength = { 0, 0, 0 }; - // running sum of the natural logs of the rates, - // used for geometric mean, the product of rates is too big for doubles - // so we use the principle of logs to help us - // We compute e ** ((log a + log b + ... + log n) / n ) - private static double[] totalLogOfRates = { 0, 0, 0 }; + // used for geometric mean, the product of rates is too big for doubles + // so we use the principle of logs to help us + // We compute e ** ((log a + log b + ... + log n) / n ) + private static double[] totalLogOfRates = {0, 0, 0}; // We can't record values until Math.log is loaded, so we miss the first few - private static int[] totalLogValueMethods = { 0, 0, 0 }; + private static int[] totalLogValueMethods = {0, 0, 0}; private static String[] earlyOptArgs = new String[0]; @@ -93,8 +105,7 @@ // because the opt compiler is not reentrant. // When we actually fix defect 2912, we'll have to implement a different // scheme that can distinguish between recursive opt compilation by the same - // thread (always bad) and parallel opt compilation (currently bad, future - // ok). + // thread (always bad) and parallel opt compilation (currently bad, future ok). // NOTE: This code can be quite subtle, so please be absolutely sure // you know what you're doing before modifying it!!! protected static boolean compilationInProgress; @@ -104,82 +115,69 @@ // Cache objects needed to cons up compilation plans // TODO: cutting link to opt compiler by declaring type as object. - public static Object /* OPT_Options */options; + public static final Object /* OPT_Options */ options = VM.BuildForAdaptiveSystem ? new OPT_Options() : null; + public static Object /* OPT_OptimizationPlanElement[] */ optimizationPlan; - public static Object /* OPT_OptimizationPlanElement[] */optimizationPlan; - /** * To be called when the VM is about to exit. - * - * @param value - * the exit value + * @param value the exit value */ public void notifyExit(int value) { report(false); } /** - * This method records the time and sizes (bytecode and machine code) for a - * compilation. - * - * @param compiler - * the compiler used - * @param method - * the resulting VM_Method - * @param compiledMethod - * the resulting compiled method + * This method records the time and sizes (bytecode and machine code) for + * a compilation. + * @param compiler the compiler used + * @param method the resulting VM_Method + * @param compiledMethod the resulting compiled method */ - public static void record(byte compiler, VM_NormalMethod method, - VM_CompiledMethod compiledMethod) { + public static void record(byte compiler, VM_NormalMethod method, VM_CompiledMethod compiledMethod) { - recordCompilation(compiler, method.getBytecodeLength(), compiledMethod - .numberOfInstructions(), compiledMethod.getCompilationTime()); + recordCompilation(compiler, + method.getBytecodeLength(), + compiledMethod.numberOfInstructions(), + compiledMethod.getCompilationTime()); if (VM.BuildForAdaptiveSystem) { if (VM_AOSLogging.booted()) { - VM_AOSLogging.recordUpdatedCompilationRates(compiler, method, method - .getBytecodeLength(), totalBCLength[compiler], compiledMethod - .numberOfInstructions(), totalMCLength[compiler], compiledMethod - .getCompilationTime(), totalCompTime[compiler], - totalLogOfRates[compiler], totalLogValueMethods[compiler], - totalMethods[compiler]); + VM_AOSLogging.recordUpdatedCompilationRates(compiler, + method, + method.getBytecodeLength(), + totalBCLength[compiler], + compiledMethod.numberOfInstructions(), + totalMCLength[compiler], + compiledMethod.getCompilationTime(), + totalCompTime[compiler], + totalLogOfRates[compiler], + totalLogValueMethods[compiler], + totalMethods[compiler]); } } } /** - * This method records the time and sizes (bytecode and machine code) for a - * compilation - * - * @param compiler - * the compiler used - * @param method - * the resulting VM_Method - * @param compiledMethod - * the resulting compiled method + * This method records the time and sizes (bytecode and machine code) for + * a compilation + * @param compiler the compiler used + * @param method the resulting VM_Method + * @param compiledMethod the resulting compiled method */ - public static void record(byte compiler, VM_NativeMethod method, - VM_CompiledMethod compiledMethod) { + public static void record(byte compiler, VM_NativeMethod method, VM_CompiledMethod compiledMethod) { recordCompilation(compiler, 0, // don't have any bytecode info, its native - compiledMethod.numberOfInstructions(), compiledMethod - .getCompilationTime()); + compiledMethod.numberOfInstructions(), compiledMethod.getCompilationTime()); } /** * This method does the actual recording - * - * @param compiler - * the compiler used - * @param BCLength - * the number of bytecodes in method source - * @param MCLength - * the length of the generated machine code - * @param compTime - * the compilation time in ms + * @param compiler the compiler used + * @param BCLength the number of bytecodes in method source + * @param MCLength the length of the generated machine code + * @param compTime the compilation time in ms */ - private static void recordCompilation(byte compiler, int BCLength, - int MCLength, double compTime) { + private static void recordCompilation(byte compiler, int BCLength, int MCLength, double compTime) { totalMethods[compiler]++; totalMCLength[compiler] += MCLength; @@ -193,8 +191,8 @@ // need to be fully booted before calling log if (VM.fullyBooted) { // we want the geometric mean, but the product of rates is too big - // for doubles, so we use the principle of logs to help us - // We compute e ** ((log a + log b + ... + log n) / n ) + // for doubles, so we use the principle of logs to help us + // We compute e ** ((log a + log b + ... + log n) / n ) totalLogOfRates[compiler] += Math.log(rate); totalLogValueMethods[compiler]++; } @@ -203,9 +201,7 @@ /** * This method produces a summary report of compilation activities - * - * @param explain - * Explains the metrics used in the report + * @param explain Explains the metrics used in the report */ public static void report(boolean explain) { VM.sysWrite("\n\t\tCompilation Subsystem Report\n"); @@ -224,27 +220,21 @@ VM.sysWrite("NA"); } else { // Bytecode bytes per millisecond, - // use unweighted geomean - VM - .sysWrite(Math.exp(totalLogOfRates[i] / totalLogValueMethods[i]), - 2); + // use unweighted geomean + VM.sysWrite(Math.exp(totalLogOfRates[i] / totalLogValueMethods[i]), 2); } VM.sysWrite("\t"); // Ratio of machine code bytes to bytecode bytes if (i != JNI_COMPILER) { - VM - .sysWrite( - (double) (totalMCLength[i] << ArchitectureSpecific.VM_RegisterConstants.LG_INSTRUCTION_WIDTH) - / (double) totalBCLength[i], 2); + VM.sysWrite((double) (totalMCLength[i] << ArchitectureSpecific.VM_RegisterConstants.LG_INSTRUCTION_WIDTH) / + (double) totalBCLength[i], 2); } else { VM.sysWrite("NA"); } VM.sysWrite("\t"); // Generated machine code Kbytes - VM - .sysWrite( - (double) (totalMCLength[i] << ArchitectureSpecific.VM_RegisterConstants.LG_INSTRUCTION_WIDTH) / 1024, - 1); + VM.sysWrite((double) (totalMCLength[i] << ArchitectureSpecific.VM_RegisterConstants.LG_INSTRUCTION_WIDTH) / + 1024, 1); VM.sysWrite("\t"); // Compiled bytecode Kbytes if (i != JNI_COMPILER) { @@ -258,34 +248,23 @@ if (explain) { // Generate an explanation of the metrics reported VM.sysWrite("\t\t\tExplanation of Metrics\n"); - VM - .sysWrite("#Meths:\t\tTotal number of methods compiled by the compiler\n"); + VM.sysWrite("#Meths:\t\tTotal number of methods compiled by the compiler\n"); VM.sysWrite("Time:\t\tTotal compilation time in milliseconds\n"); - VM - .sysWrite("bcb/ms:\t\tNumber of bytecode bytes complied per millisecond\n"); + VM.sysWrite("bcb/ms:\t\tNumber of bytecode bytes complied per millisecond\n"); VM.sysWrite("mcb/bcb:\tRatio of machine code bytes to bytecode bytes\n"); - VM - .sysWrite("MCKB:\t\tTotal number of machine code bytes generated in kilobytes\n"); - VM - .sysWrite("BCKB:\t\tTotal number of bytecode bytes compiled in kilobytes\n"); + VM.sysWrite("MCKB:\t\tTotal number of machine code bytes generated in kilobytes\n"); + VM.sysWrite("BCKB:\t\tTotal number of bytecode bytes compiled in kilobytes\n"); } VM_BaselineCompiler.generateBaselineCompilerSubsystemReport(explain); if (VM.BuildForAdaptiveSystem) { // Get the opt's report - VM_TypeReference theTypeRef = VM_TypeReference - .findOrCreate( - VM_BootstrapClassLoader.getBootstrapClassLoader(), - VM_Atom - .findOrCreateAsciiAtom("Lorg/jikesrvm/opt/OPT_OptimizationPlanner;")); - VM_Type theType = theTypeRef.peekResolvedType(); + VM_Type theType = VM_TypeReference.OPT_OptimizationPlanner.peekType(); if (theType != null && theType.asClass().isInitialized()) { - OPT_OptimizationPlanner - .generateOptimizingCompilerSubsystemReport(explain); + OPT_OptimizationPlanner.generateOptimizingCompilerSubsystemReport(explain); } else { - VM - .sysWrite("\n\tNot generating Optimizing Compiler SubSystem Report because \n"); + VM.sysWrite("\n\tNot generating Optimizing Compiler SubSystem Report because \n"); VM.sysWrite("\tthe opt compiler was never invoked.\n\n"); } } @@ -295,32 +274,35 @@ * Return the current estimate of basline-compiler rate, in bcb/msec */ public static double getBaselineRate() { - return Math.exp(totalLogOfRates[BASELINE_COMPILER] - / totalLogValueMethods[BASELINE_COMPILER]); + return Math.exp(totalLogOfRates[BASELINE_COMPILER] / tota... [truncated message content] |
From: <mic...@us...> - 2007-08-06 14:18:05
|
Revision: 156 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=156&view=rev Author: michael_baer Date: 2007-08-06 07:18:07 -0700 (Mon, 06 Aug 2007) Log Message: ----------- - Removed file due to lack of differences against current JRVM version Removed Paths: ------------- ext/org/jikesrvm/compilers/opt/OPT_Simplifier.java Deleted: ext/org/jikesrvm/compilers/opt/OPT_Simplifier.java =================================================================== --- ext/org/jikesrvm/compilers/opt/OPT_Simplifier.java 2007-08-06 09:37:44 UTC (rev 155) +++ ext/org/jikesrvm/compilers/opt/OPT_Simplifier.java 2007-08-06 14:18:07 UTC (rev 156) @@ -1,3266 +0,0 @@ -/* - * This file is part of Jikes RVM (http://jikesrvm.sourceforge.net). - * The Jikes RVM project is distributed under the Common Public License (CPL). - * A copy of the license is included in the distribution, and is also - * available at http://www.opensource.org/licenses/cpl1.0.php - * - * (C) Copyright IBM Corp. 2001 - */ -package org.jikesrvm.compilers.opt; - -import org.jikesrvm.classloader.*; -import org.jikesrvm.compilers.opt.ir.*; -import org.jikesrvm.objectmodel.VM_TIBLayoutConstants; -import org.jikesrvm.VM; -import org.vmmagic.unboxed.*; -import java.lang.reflect.Array; -import static org.jikesrvm.VM_SizeConstants.*; -import static org.jikesrvm.compilers.opt.ir.OPT_Operators.*; - -/** - * A constant folder, strength reducer and axiomatic simplifier. - * - * <p> - * This module performs no analysis, it simply attempts to simplify the - * instruction as is. The intent is that analysis modules can call this - * transformation engine, allowing us to share the tedious simplification code - * among multiple analysis modules. - * - * <p> - * NOTE: For maintainability purposes, I've intentionally avoided being clever - * about combining 'similar' operators together into a combined case of the main - * switch switch statement. Also, operators are in sorted ordered within each - * major grouping. Please maintain this coding style. I'd rather have this - * module be 2000 lines of obviously correct code than 500 lines of clever code. - * - * @author Dave Grove - * @author Ian Rogers - */ -public abstract class OPT_Simplifier extends OPT_IRTools { - // NOTE: The convention is that constant folding is controlled based - // on the type of the result of the operator, not the type of its inputs. - /** - * Constant fold integer operations? - */ - public static final boolean CF_INT = true; - - /** - * Constant fold address operations? - */ - public static final boolean CF_LONG = true; - - /** - * Constant fold address operations? - */ - public static final boolean CF_ADDR = true; - - /** - * Constant fold float operations? Default is true, flip to avoid consuming - * precious JTOC slots to hold new constant values. - */ - public static final boolean CF_FLOAT = true; - - /** - * Constant fold double operations? Default is true, flip to avoid consuming - * precious JTOC slots to hold new constant values. - */ - public static final boolean CF_DOUBLE = true; - - /** - * Constant fold field operations? Default is true, flip to avoid consuming - * precious JTOC slots to hold new constant values. - */ - public static final boolean CF_FIELDS = false; - - /** - * Constant fold TIB operations? Default is true, flip to avoid consuming - * precious JTOC slots to hold new constant values. - */ - public static final boolean CF_TIB = false; - - /** - * Effect of the simplification on Def-Use chains - */ - public enum DefUseEffect { - /** - * Enumeration value to indicate an operation is unchanged, although the - * order of operands may have been canonicalized and type information - * strengthened. - */ - UNCHANGED, - /** - * Enumeration value to indicate an operation has been replaced by a move - * instruction with a constant right hand side. - */ - MOVE_FOLDED, - /** - * Enumeration value to indicate an operation has been replaced by a move - * instruction with a non-constant right hand side. - */ - MOVE_REDUCED, - /** - * Enumeration value to indicate an operation has been replaced by an - * unconditional trap instruction. - */ - TRAP_REDUCED, - /** - * Enumeration value to indicate an operation has been replaced by a - * cheaper, but non-move instruction. - */ - REDUCED - } - - /** - * Given an instruction, attempt to simplify it. The instruction will be - * mutated in place. - * - * <p> - * We don't deal with branching operations here -- doing peephole - * optimizations of branches is the job of a separate module. - * - * @param regpool - * register pool in case simplification requires a temporary register - * @param s - * the instruction to simplify - * @return one of UNCHANGED, MOVE_FOLDED, MOVE_REDUCED, TRAP_REDUCED, REDUCED - */ - public static DefUseEffect simplify(OPT_AbstractRegisterPool regpool, - OPT_Instruction s) { - DefUseEffect result; - char opcode = s.getOpcode(); - switch (opcode) { - // ////////////////// - // GUARD operations - // ////////////////// - case GUARD_COMBINE_opcode: - result = guardCombine(s); - break; - // ////////////////// - // TRAP operations - // ////////////////// - case TRAP_IF_opcode: - result = trapIf(s); - break; - case NULL_CHECK_opcode: - result = nullCheck(s); - break; - case INT_ZERO_CHECK_opcode: - result = intZeroCheck(s); - break; - case LONG_ZERO_CHECK_opcode: - result = longZeroCheck(s); - break; - case CHECKCAST_opcode: - result = checkcast(regpool, s); - break; - case CHECKCAST_UNRESOLVED_opcode: - result = checkcast(regpool, s); - break; - case CHECKCAST_NOTNULL_opcode: - result = checkcastNotNull(s); - break; - case INSTANCEOF_opcode: - result = instanceOf(regpool, s); - break; - case INSTANCEOF_NOTNULL_opcode: - result = instanceOfNotNull(s); - break; - case OBJARRAY_STORE_CHECK_opcode: - result = objarrayStoreCheck(s); - break; - case OBJARRAY_STORE_CHECK_NOTNULL_opcode: - result = objarrayStoreCheckNotNull(s); - break; - case MUST_IMPLEMENT_INTERFACE_opcode: - result = mustImplementInterface(s); - break; - // ////////////////// - // Conditional moves - // ////////////////// - case INT_COND_MOVE_opcode: - result = intCondMove(s); - break; - case LONG_COND_MOVE_opcode: - result = longCondMove(s); - break; - case FLOAT_COND_MOVE_opcode: - result = floatCondMove(s); - break; - case DOUBLE_COND_MOVE_opcode: - result = doubleCondMove(s); - break; - case REF_COND_MOVE_opcode: - result = refCondMove(s); - break; - case GUARD_COND_MOVE_opcode: - result = guardCondMove(s); - break; - // ////////////////// - // INT ALU operations - // ////////////////// - case BOOLEAN_NOT_opcode: - result = booleanNot(s); - break; - case BOOLEAN_CMP_INT_opcode: - result = booleanCmpInt(s); - break; - case BOOLEAN_CMP_ADDR_opcode: - result = booleanCmpAddr(s); - break; - case BOOLEAN_CMP2_INT_OR_opcode: - result = booleanCmp2IntOr(s); - break; - // case BOOLEAN_CMP2_INT_AND: - // result = booleanCmp2IntAnd(s); - // break; - case INT_ADD_opcode: - result = intAdd(s); - break; - case INT_AND_opcode: - result = intAnd(s); - break; - case INT_DIV_opcode: - result = intDiv(s); - break; - case INT_MUL_opcode: - result = intMul(regpool, s); - break; - case INT_NEG_opcode: - result = intNeg(s); - break; - case INT_NOT_opcode: - result = intNot(s); - break; - case INT_OR_opcode: - result = intOr(s); - break; - case INT_REM_opcode: - result = intRem(s); - break; - case INT_SHL_opcode: - result = intShl(s); - break; - case INT_SHR_opcode: - result = intShr(s); - break; - case INT_SUB_opcode: - result = intSub(s); - break; - case INT_USHR_opcode: - result = intUshr(s); - break; - case INT_XOR_opcode: - result = intXor(s); - break; - // ////////////////// - // WORD ALU operations - // ////////////////// - case REF_ADD_opcode: - result = refAdd(s); - break; - case REF_AND_opcode: - result = refAnd(s); - break; - case REF_SHL_opcode: - result = refShl(s); - break; - case REF_SHR_opcode: - result = refShr(s); - break; - case REF_NOT_opcode: - result = refNot(s); - break; - case REF_OR_opcode: - result = refOr(s); - break; - case REF_SUB_opcode: - result = refSub(s); - break; - case REF_USHR_opcode: - result = regUshr(s); - break; - case REF_XOR_opcode: - result = refXor(s); - break; - // ////////////////// - // LONG ALU operations - // ////////////////// - case LONG_ADD_opcode: - result = longAdd(s); - break; - case LONG_AND_opcode: - result = longAnd(s); - break; - case LONG_CMP_opcode: - result = longCmp(s); - break; - case LONG_DIV_opcode: - result = longDiv(s); - break; - case LONG_MUL_opcode: - result = longMul(s); - break; - case LONG_NEG_opcode: - result = longNeg(s); - break; - case LONG_NOT_opcode: - result = longNot(s); - break; - case LONG_OR_opcode: - result = longOr(s); - break; - case LONG_REM_opcode: - result = longRem(s); - break; - case LONG_SHL_opcode: - result = longShl(s); - break; - case LONG_SHR_opcode: - result = longShr(s); - break; - case LONG_SUB_opcode: - result = longSub(s); - break; - case LONG_USHR_opcode: - result = longUshr(s); - break; - case LONG_XOR_opcode: - result = longXor(s); - break; - // ////////////////// - // FLOAT ALU operations - // ////////////////// - case FLOAT_ADD_opcode: - result = floatAdd(s); - break; - case FLOAT_CMPG_opcode: - result = floatCmpg(s); - break; - case FLOAT_CMPL_opcode: - result = floatCmpl(s); - break; - case FLOAT_DIV_opcode: - result = floatDiv(s); - break; - case FLOAT_MUL_opcode: - result = floatMul(s); - break; - case FLOAT_NEG_opcode: - result = floatNeg(s); - break; - case FLOAT_REM_opcode: - result = floatRem(s); - break; - case FLOAT_SUB_opcode: - result = floatSub(s); - break; - // ////////////////// - // DOUBLE ALU operations - // ////////////////// - case DOUBLE_ADD_opcode: - result = doubleAdd(s); - break; - case DOUBLE_CMPG_opcode: - result = doubleCmpg(s); - break; - case DOUBLE_CMPL_opcode: - result = doubleCmpl(s); - break; - case DOUBLE_DIV_opcode: - result = doubleDiv(s); - break; - case DOUBLE_MUL_opcode: - result = doubleMul(s); - break; - case DOUBLE_NEG_opcode: - result = doubleNeg(s); - break; - case DOUBLE_REM_opcode: - result = doubleRem(s); - break; - case DOUBLE_SUB_opcode: - result = doubleSub(s); - break; - // ////////////////// - // CONVERSION operations - // ////////////////// - case DOUBLE_2FLOAT_opcode: - result = double2Float(s); - break; - case DOUBLE_2INT_opcode: - result = double2Int(s); - break; - case DOUBLE_2LONG_opcode: - result = double2Long(s); - break; - case DOUBLE_AS_LONG_BITS_opcode: - result = doubleAsLongBits(s); - break; - case INT_2DOUBLE_opcode: - result = int2Double(s); - break; - case INT_2BYTE_opcode: - result = int2Byte(s); - break; - case INT_2USHORT_opcode: - result = int2UShort(s); - break; - case INT_2FLOAT_opcode: - result = int2Float(s); - break; - case INT_2LONG_opcode: - result = int2Long(s); - break; - case INT_2ADDRSigExt_opcode: - result = int2AddrSigExt(s); - break; - case INT_2ADDRZerExt_opcode: - result = int2AddrZerExt(s); - break; - case LONG_2ADDR_opcode: - result = long2Addr(s); - break; - case INT_2SHORT_opcode: - result = int2Short(s); - break; - case INT_BITS_AS_FLOAT_opcode: - result = intBitsAsFloat(s); - break; - case ADDR_2INT_opcode: - result = addr2Int(s); - break; - case ADDR_2LONG_opcode: - result = addr2Long(s); - break; - case FLOAT_2DOUBLE_opcode: - result = float2Double(s); - break; - case FLOAT_2INT_opcode: - result = float2Int(s); - break; - case FLOAT_2LONG_opcode: - result = float2Long(s); - break; - case FLOAT_AS_INT_BITS_opcode: - result = floatAsIntBits(s); - break; - case LONG_2FLOAT_opcode: - result = long2Float(s); - break; - case LONG_2INT_opcode: - result = long2Int(s); - break; - case LONG_2DOUBLE_opcode: - result = long2Double(s); - break; - case LONG_BITS_AS_DOUBLE_opcode: - result = longBitsAsDouble(s); - break; - // ////////////////// - // Field operations - // ////////////////// - case ARRAYLENGTH_opcode: - result = arrayLength(s); - break; - case BOUNDS_CHECK_opcode: - result = boundsCheck(s); - break; - case CALL_opcode: - result = call(s); - break; - case GETFIELD_opcode: - result = getField(s); - break; - case GET_OBJ_TIB_opcode: - result = getObjTib(s); - break; - case GET_CLASS_TIB_opcode: - result = getClassTib(s); - break; - case GET_TYPE_FROM_TIB_opcode: - result = getTypeFromTib(s); - break; - case GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode: - result = getArrayElementTibFromTib(s); - break; - case GET_SUPERCLASS_IDS_FROM_TIB_opcode: - result = getSuperclassIdsFromTib(s); - break; - case GET_DOES_IMPLEMENT_FROM_TIB_opcode: - result = getDoesImplementFromTib(s); - break; - case REF_LOAD_opcode: - result = refLoad(s); - break; - default: - result = DefUseEffect.UNCHANGED; - } - if (VM.VerifyAssertions) { - switch (result) { - case MOVE_FOLDED: - // Check move has constant RHS - VM._assert(Move.conforms(s) - && (Move.getVal(s) instanceof OPT_ConstantOperand), "RHS of move " - + s + " should be constant during simplification of " - + OPT_OperatorNames.operatorName[opcode]); - break; - case MOVE_REDUCED: - // Check move has non-constant RHS - VM._assert(Move.conforms(s) - && !(Move.getVal(s) instanceof OPT_ConstantOperand), "RHS of move " - + s + " shouldn't be constant during simplification of " - + OPT_OperatorNames.operatorName[opcode]); - break; - default: - // Nothing to check - } - } - return result; - } - - private static DefUseEffect guardCombine(OPT_Instruction s) { - OPT_Operand op1 = Binary.getVal1(s); - OPT_Operand op2 = Binary.getVal2(s); - if (op1.similar(op2) || (op2 instanceof OPT_TrueGuardOperand)) { - Move.mutate(s, GUARD_MOVE, Binary.getClearResult(s), op1); - if (op1 instanceof OPT_TrueGuardOperand) { - // BOTH true guards: FOLD - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS TrueGuard: MOVE REDUCE - return DefUseEffect.MOVE_REDUCED; - } - } else if (op1 instanceof OPT_TrueGuardOperand) { - // ONLY OP1 IS TrueGuard: MOVE REDUCE - Move.mutate(s, GUARD_MOVE, Binary.getClearResult(s), op2); - return DefUseEffect.MOVE_REDUCED; - } else { - return DefUseEffect.UNCHANGED; - } - } - - private static DefUseEffect trapIf(OPT_Instruction s) { - { - OPT_Operand op1 = TrapIf.getVal1(s); - OPT_Operand op2 = TrapIf.getVal2(s); - if (op1.isConstant()) { - if (op2.isConstant()) { - int willTrap = TrapIf.getCond(s).evaluate(op1, op2); - if (willTrap == OPT_ConditionOperand.TRUE) { - Trap.mutate(s, TRAP, TrapIf.getClearGuardResult(s), TrapIf - .getClearTCode(s)); - return DefUseEffect.TRAP_REDUCED; - } else if (willTrap == OPT_ConditionOperand.FALSE) { - Move.mutate(s, GUARD_MOVE, TrapIf.getClearGuardResult(s), TG()); - return DefUseEffect.MOVE_FOLDED; - } - } else { - // canonicalize - TrapIf.mutate(s, TRAP_IF, TrapIf.getClearGuardResult(s), TrapIf - .getClearVal2(s), TrapIf.getClearVal1(s), TrapIf.getClearCond(s) - .flipOperands(), TrapIf.getClearTCode(s)); - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect nullCheck(OPT_Instruction s) { - OPT_Operand ref = NullCheck.getRef(s); - if (ref.isNullConstant() - || (ref.isAddressConstant() && ref.asAddressConstant().value.isZero())) { - Trap.mutate(s, TRAP, NullCheck.getClearGuardResult(s), - OPT_TrapCodeOperand.NullPtr()); - return DefUseEffect.TRAP_REDUCED; - } else if (ref.isConstant()) { - // object, string, class or non-null address constant - - // Make the slightly suspect assumption that all non-zero address - // constants are actually valid pointers. Not necessarily true, - // but unclear what else we can do. - Move.mutate(s, GUARD_MOVE, NullCheck.getClearGuardResult(s), TG()); - return DefUseEffect.MOVE_FOLDED; - } else { - return DefUseEffect.UNCHANGED; - } - } - - private static DefUseEffect intZeroCheck(OPT_Instruction s) { - { - OPT_Operand op = ZeroCheck.getValue(s); - if (op.isIntConstant()) { - int val = op.asIntConstant().value; - if (val == 0) { - Trap.mutate(s, TRAP, ZeroCheck.getClearGuardResult(s), - OPT_TrapCodeOperand.DivByZero()); - return DefUseEffect.TRAP_REDUCED; - } else { - Move.mutate(s, GUARD_MOVE, ZeroCheck.getClearGuardResult(s), TG()); - return DefUseEffect.MOVE_FOLDED; - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect longZeroCheck(OPT_Instruction s) { - { - OPT_Operand op = ZeroCheck.getValue(s); - if (op.isLongConstant()) { - long val = op.asLongConstant().value; - if (val == 0L) { - Trap.mutate(s, TRAP, ZeroCheck.getClearGuardResult(s), - OPT_TrapCodeOperand.DivByZero()); - return DefUseEffect.TRAP_REDUCED; - } else { - Move.mutate(s, GUARD_MOVE, ZeroCheck.getClearGuardResult(s), TG()); - return DefUseEffect.MOVE_FOLDED; - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect checkcast(OPT_AbstractRegisterPool regpool, - OPT_Instruction s) { - OPT_Operand ref = TypeCheck.getRef(s); - if (ref.isNullConstant()) { - Empty.mutate(s, NOP); - return DefUseEffect.REDUCED; - } else if (ref.isConstant()) { - s.operator = CHECKCAST_NOTNULL; - return checkcastNotNull(s); - } else { - VM_TypeReference lhsType = TypeCheck.getType(s).getTypeRef(); - VM_TypeReference rhsType = ref.getType(); - byte ans = OPT_ClassLoaderProxy.includesType(lhsType, rhsType); - if (ans == OPT_Constants.YES) { - Empty.mutate(s, NOP); - return DefUseEffect.REDUCED; - } else { - // NOTE: OPT_Constants.NO can't help us because (T)null always succeeds - return DefUseEffect.UNCHANGED; - } - } - } - - private static DefUseEffect checkcastNotNull(OPT_Instruction s) { - OPT_Operand ref = TypeCheck.getRef(s); - VM_TypeReference lhsType = TypeCheck.getType(s).getTypeRef(); - VM_TypeReference rhsType = ref.getType(); - byte ans = OPT_ClassLoaderProxy.includesType(lhsType, rhsType); - if (ans == OPT_Constants.YES) { - Empty.mutate(s, NOP); - return DefUseEffect.REDUCED; - } else if (ans == OPT_Constants.NO) { - VM_Type rType = rhsType.peekResolvedType(); - if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { - // only final (or precise) rhs types can be optimized since rhsType may - // be conservative - Trap.mutate(s, TRAP, null, OPT_TrapCodeOperand.CheckCast()); - return DefUseEffect.TRAP_REDUCED; - } else { - return DefUseEffect.UNCHANGED; - } - } else { - return DefUseEffect.UNCHANGED; - } - } - - private static DefUseEffect instanceOf(OPT_AbstractRegisterPool regpool, - OPT_Instruction s) { - OPT_Operand ref = InstanceOf.getRef(s); - if (ref.isNullConstant()) { - Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } else if (ref.isConstant()) { - s.operator = INSTANCEOF_NOTNULL; - return instanceOfNotNull(s); - } else { - VM_TypeReference lhsType = InstanceOf.getType(s).getTypeRef(); - VM_TypeReference rhsType = ref.getType(); - byte ans = OPT_ClassLoaderProxy.includesType(lhsType, rhsType); - // NOTE: OPT_Constants.YES doesn't help because ref may be null and null - // instanceof T is false - if (ans == OPT_Constants.NO) { - VM_Type rType = rhsType.peekResolvedType(); - if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { - // only final (or precise) rhs types can be optimized since rhsType - // may be conservative - Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } else { - return DefUseEffect.UNCHANGED; - } - } else { - return DefUseEffect.UNCHANGED; - } - } - } - - private static DefUseEffect instanceOfNotNull(OPT_Instruction s) { - { - OPT_Operand ref = InstanceOf.getRef(s); - VM_TypeReference lhsType = InstanceOf.getType(s).getTypeRef(); - VM_TypeReference rhsType = ref.getType(); - byte ans = OPT_ClassLoaderProxy.includesType(lhsType, rhsType); - if (ans == OPT_Constants.YES) { - Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(1)); - return DefUseEffect.MOVE_FOLDED; - } else if (ans == OPT_Constants.NO) { - VM_Type rType = rhsType.peekResolvedType(); - if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { - // only final (or precise) rhs types can be optimized since rhsType - // may be conservative - Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect objarrayStoreCheck(OPT_Instruction s) { - OPT_Operand val = StoreCheck.getVal(s); - if (val.isNullConstant()) { - // Writing null into an array is trivially safe - Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck - .getClearGuard(s)); - return DefUseEffect.MOVE_REDUCED; - } else { - OPT_Operand ref = StoreCheck.getRef(s); - VM_TypeReference arrayTypeRef = ref.getType(); - VM_Type typeOfIMElem = arrayTypeRef.getInnermostElementType() - .peekResolvedType(); - if (typeOfIMElem != null) { - VM_Type typeOfVal = val.getType().peekResolvedType(); - if ((typeOfIMElem == typeOfVal) - && (typeOfIMElem.isPrimitiveType() || typeOfIMElem.asClass() - .isFinal())) { - // Writing something of a final type to an array of that - // final type is safe - Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), - StoreCheck.getClearGuard(s)); - return DefUseEffect.MOVE_REDUCED; - } - } - if (ref.isConstant() - && (arrayTypeRef == VM_TypeReference.JavaLangObjectArray)) { - // We know this to be an array of objects so any store must - // be safe - Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), - StoreCheck.getClearGuard(s)); - return DefUseEffect.MOVE_REDUCED; - } - if (val.isConstant() && ref.isConstant()) { - // writing a constant value into a constant array - byte ans = OPT_ClassLoaderProxy.includesType(arrayTypeRef - .getArrayElementType(), val.getType()); - if (ans == OPT_Constants.YES) { - // all stores should succeed - Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), - StoreCheck.getClearGuard(s)); - return DefUseEffect.MOVE_REDUCED; - } else if (ans == OPT_Constants.NO) { - // all stores will fail - Trap.mutate(s, TRAP, StoreCheck.getClearGuardResult(s), - OPT_TrapCodeOperand.StoreCheck()); - return DefUseEffect.TRAP_REDUCED; - } - } - return DefUseEffect.UNCHANGED; - } - } - - private static DefUseEffect objarrayStoreCheckNotNull(OPT_Instruction s) { - OPT_Operand val = StoreCheck.getVal(s); - OPT_Operand ref = StoreCheck.getRef(s); - VM_TypeReference arrayTypeRef = ref.getType(); - VM_Type typeOfIMElem = arrayTypeRef.getInnermostElementType() - .peekResolvedType(); - if (typeOfIMElem != null) { - VM_Type typeOfVal = val.getType().peekResolvedType(); - if ((typeOfIMElem == typeOfVal) - && (typeOfIMElem.isPrimitiveType() || typeOfIMElem.asClass() - .isFinal())) { - // Writing something of a final type to an array of that - // final type is safe - Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), - StoreCheck.getClearGuard(s)); - return DefUseEffect.MOVE_REDUCED; - } - } - if (ref.isConstant() - && (arrayTypeRef == VM_TypeReference.JavaLangObjectArray)) { - // We know this to be an array of objects so any store must - // be safe - Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck - .getClearGuard(s)); - return DefUseEffect.MOVE_REDUCED; - } - if (val.isConstant() && ref.isConstant()) { - // writing a constant value into a constant array - byte ans = OPT_ClassLoaderProxy.includesType(arrayTypeRef - .getArrayElementType(), val.getType()); - if (ans == OPT_Constants.YES) { - // all stores should succeed - Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), - StoreCheck.getClearGuard(s)); - return DefUseEffect.MOVE_REDUCED; - } else if (ans == OPT_Constants.NO) { - // all stores will fail - Trap.mutate(s, TRAP, StoreCheck.getClearGuardResult(s), - OPT_TrapCodeOperand.StoreCheck()); - return DefUseEffect.TRAP_REDUCED; - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect mustImplementInterface(OPT_Instruction s) { - OPT_Operand ref = TypeCheck.getRef(s); - if (ref.isNullConstant()) { - // Possible sitatution from constant propagation. This operation - // is really a nop as a null_check should have happened already - Trap.mutate(s, TRAP, null, OPT_TrapCodeOperand.NullPtr()); - return DefUseEffect.TRAP_REDUCED; - } else { - VM_TypeReference lhsType = TypeCheck.getType(s).getTypeRef(); // the - // interface - // that must - // be - // implemented - VM_TypeReference rhsType = ref.getType(); // our type - byte ans = OPT_ClassLoaderProxy.includesType(lhsType, rhsType); - if (ans == OPT_Constants.YES) { - Empty.mutate(s, NOP); - return DefUseEffect.REDUCED; - } else if (ans == OPT_Constants.NO) { - VM_Type rType = rhsType.peekResolvedType(); - if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { - // only final (or precise) rhs types can be optimized since rhsType - // may be conservative - Trap.mutate(s, TRAP, null, OPT_TrapCodeOperand.MustImplement()); - return DefUseEffect.TRAP_REDUCED; - } - } - return DefUseEffect.UNCHANGED; - } - } - - private static DefUseEffect intCondMove(OPT_Instruction s) { - { - OPT_Operand val1 = CondMove.getVal1(s); - OPT_Operand val2 = CondMove.getVal2(s); - int cond = CondMove.getCond(s).evaluate(val1, val2); - if (cond != OPT_ConditionOperand.UNKNOWN) { - // BOTH CONSTANTS OR SIMILAR: FOLD - OPT_Operand val = (cond == OPT_ConditionOperand.TRUE) ? CondMove - .getClearTrueValue(s) : CondMove.getClearFalseValue(s); - Move.mutate(s, INT_MOVE, CondMove.getClearResult(s), val); - return val.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - if (val1.isConstant() && !val2.isConstant()) { - // Canonicalize by switching operands and fliping code. - OPT_Operand tmp = CondMove.getClearVal1(s); - CondMove.setVal1(s, CondMove.getClearVal2(s)); - CondMove.setVal2(s, tmp); - CondMove.getCond(s).flipOperands(); - } - OPT_Operand tv = CondMove.getTrueValue(s); - OPT_Operand fv = CondMove.getFalseValue(s); - if (tv.similar(fv)) { - Move.mutate(s, INT_MOVE, CondMove.getClearResult(s), tv); - return tv.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - if (tv.isIntConstant() && fv.isIntConstant() - && !CondMove.getCond(s).isFLOATINGPOINT()) { - int itv = tv.asIntConstant().value; - int ifv = fv.asIntConstant().value; - OPT_Operator op = null; - if (val1.isLong()) { - op = BOOLEAN_CMP_LONG; - } else if (val1.isFloat()) { - op = BOOLEAN_CMP_FLOAT; - } else if (val1.isDouble()) { - op = BOOLEAN_CMP_DOUBLE; - } else { - op = BOOLEAN_CMP_INT; - } - if (itv == 1 && ifv == 0) { - BooleanCmp.mutate(s, op, CondMove.getClearResult(s), CondMove - .getClearVal1(s), CondMove.getClearVal2(s), CondMove - .getClearCond(s), new OPT_BranchProfileOperand()); - return DefUseEffect.REDUCED; - } - if (itv == 0 && ifv == 1) { - BooleanCmp.mutate(s, op, CondMove.getClearResult(s), CondMove - .getClearVal1(s), CondMove.getClearVal2(s), CondMove - .getClearCond(s).flipCode(), new OPT_BranchProfileOperand()); - return DefUseEffect.REDUCED; - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect longCondMove(OPT_Instruction s) { - { - OPT_Operand val1 = CondMove.getVal1(s); - OPT_Operand val2 = CondMove.getVal2(s); - int cond = CondMove.getCond(s).evaluate(val1, val2); - if (cond != OPT_ConditionOperand.UNKNOWN) { - // BOTH CONSTANTS OR SIMILAR: FOLD - OPT_Operand val = (cond == OPT_ConditionOperand.TRUE) ? CondMove - .getClearTrueValue(s) : CondMove.getClearFalseValue(s); - Move.mutate(s, LONG_MOVE, CondMove.getClearResult(s), val); - return val.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - if (val1.isConstant() && !val2.isConstant()) { - // Canonicalize by switching operands and fliping code. - OPT_Operand tmp = CondMove.getClearVal1(s); - CondMove.setVal1(s, CondMove.getClearVal2(s)); - CondMove.setVal2(s, tmp); - CondMove.getCond(s).flipOperands(); - } - OPT_Operand tv = CondMove.getTrueValue(s); - OPT_Operand fv = CondMove.getFalseValue(s); - if (tv.similar(fv)) { - Move.mutate(s, LONG_MOVE, CondMove.getClearResult(s), tv); - return tv.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - if (tv.isLongConstant() && fv.isLongConstant() - && !CondMove.getCond(s).isFLOATINGPOINT()) { - long itv = tv.asLongConstant().value; - long ifv = fv.asLongConstant().value; - OPT_Operator op = null; - if (val1.isLong()) { - op = BOOLEAN_CMP_LONG; - } else if (val1.isFloat()) { - op = BOOLEAN_CMP_FLOAT; - } else if (val1.isDouble()) { - op = BOOLEAN_CMP_DOUBLE; - } else { - op = BOOLEAN_CMP_INT; - } - if (itv == 1 && ifv == 0) { - BooleanCmp.mutate(s, op, CondMove.getClearResult(s), CondMove - .getClearVal1(s), CondMove.getClearVal2(s), CondMove - .getClearCond(s), new OPT_BranchProfileOperand()); - return DefUseEffect.REDUCED; - } - if (itv == 0 && ifv == 1) { - BooleanCmp.mutate(s, op, CondMove.getClearResult(s), CondMove - .getClearVal1(s), CondMove.getClearVal2(s), CondMove - .getClearCond(s).flipCode(), new OPT_BranchProfileOperand()); - return DefUseEffect.REDUCED; - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect floatCondMove(OPT_Instruction s) { - { - OPT_Operand val1 = CondMove.getVal1(s); - OPT_Operand val2 = CondMove.getVal2(s); - int cond = CondMove.getCond(s).evaluate(val1, val2); - if (cond != OPT_ConditionOperand.UNKNOWN) { - // BOTH CONSTANTS OR SIMILAR: FOLD - OPT_Operand val = (cond == OPT_ConditionOperand.TRUE) ? CondMove - .getClearTrueValue(s) : CondMove.getClearFalseValue(s); - Move.mutate(s, FLOAT_MOVE, CondMove.getClearResult(s), val); - return val.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - if (val1.isConstant() && !val2.isConstant()) { - // Canonicalize by switching operands and fliping code. - OPT_Operand tmp = CondMove.getClearVal1(s); - CondMove.setVal1(s, CondMove.getClearVal2(s)); - CondMove.setVal2(s, tmp); - CondMove.getCond(s).flipOperands(); - } - OPT_Operand tv = CondMove.getTrueValue(s); - OPT_Operand fv = CondMove.getFalseValue(s); - if (tv.similar(fv)) { - Move.mutate(s, FLOAT_MOVE, CondMove.getClearResult(s), tv); - return tv.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect doubleCondMove(OPT_Instruction s) { - { - OPT_Operand val1 = CondMove.getVal1(s); - OPT_Operand val2 = CondMove.getVal2(s); - int cond = CondMove.getCond(s).evaluate(val1, val2); - if (cond != OPT_ConditionOperand.UNKNOWN) { - // BOTH CONSTANTS OR SIMILAR: FOLD - OPT_Operand val = (cond == OPT_ConditionOperand.TRUE) ? CondMove - .getClearTrueValue(s) : CondMove.getClearFalseValue(s); - Move.mutate(s, DOUBLE_MOVE, CondMove.getClearResult(s), val); - return val.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - if (val1.isConstant() && !val2.isConstant()) { - // Canonicalize by switching operands and fliping code. - OPT_Operand tmp = CondMove.getClearVal1(s); - CondMove.setVal1(s, CondMove.getClearVal2(s)); - CondMove.setVal2(s, tmp); - CondMove.getCond(s).flipOperands(); - } - OPT_Operand tv = CondMove.getTrueValue(s); - OPT_Operand fv = CondMove.getFalseValue(s); - if (tv.similar(fv)) { - Move.mutate(s, DOUBLE_MOVE, CondMove.getClearResult(s), tv); - return tv.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect refCondMove(OPT_Instruction s) { - { - OPT_Operand val1 = CondMove.getVal1(s); - if (val1.isConstant()) { - OPT_Operand val2 = CondMove.getVal2(s); - if (val2.isConstant()) { - // BOTH CONSTANTS: FOLD - int cond = CondMove.getCond(s).evaluate(val1, val2); - if (cond != OPT_ConditionOperand.UNKNOWN) { - OPT_Operand val = (cond == OPT_ConditionOperand.TRUE) ? CondMove - .getClearTrueValue(s) : CondMove.getClearFalseValue(s); - Move.mutate(s, REF_MOVE, CondMove.getClearResult(s), val); - return val.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - } else { - // Canonicalize by switching operands and fliping code. - OPT_Operand tmp = CondMove.getClearVal1(s); - CondMove.setVal1(s, CondMove.getClearVal2(s)); - CondMove.setVal2(s, tmp); - CondMove.getCond(s).flipOperands(); - } - } - if (CondMove.getTrueValue(s).similar(CondMove.getFalseValue(s))) { - OPT_Operand val = CondMove.getClearTrueValue(s); - Move.mutate(s, REF_MOVE, CondMove.getClearResult(s), val); - return val.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect guardCondMove(OPT_Instruction s) { - { - OPT_Operand val1 = CondMove.getVal1(s); - if (val1.isConstant()) { - OPT_Operand val2 = CondMove.getVal2(s); - if (val2.isConstant()) { - // BOTH CONSTANTS: FOLD - int cond = CondMove.getCond(s).evaluate(val1, val2); - if (cond == OPT_ConditionOperand.UNKNOWN) { - OPT_Operand val = (cond == OPT_ConditionOperand.TRUE) ? CondMove - .getClearTrueValue(s) : CondMove.getClearFalseValue(s); - Move.mutate(s, GUARD_MOVE, CondMove.getClearResult(s), val); - return val.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - } else { - // Canonicalize by switching operands and fliping code. - OPT_Operand tmp = CondMove.getClearVal1(s); - CondMove.setVal1(s, CondMove.getClearVal2(s)); - CondMove.setVal2(s, tmp); - CondMove.getCond(s).flipOperands(); - } - } - if (CondMove.getTrueValue(s).similar(CondMove.getFalseValue(s))) { - OPT_Operand val = CondMove.getClearTrueValue(s); - Move.mutate(s, GUARD_MOVE, CondMove.getClearResult(s), val); - return val.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect booleanNot(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op = Unary.getVal(s); - if (op.isIntConstant()) { - // CONSTANT: FOLD - int val = op.asIntConstant().value; - if (val == 0) { - Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(1)); - } else { - Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(0)); - } - return DefUseEffect.MOVE_FOLDED; - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect booleanCmpInt(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op1 = BooleanCmp.getVal1(s); - OPT_Operand op2 = BooleanCmp.getVal2(s); - if (op1.isConstant()) { - if (op2.isConstant()) { - // BOTH CONSTANTS: FOLD - int cond = BooleanCmp.getCond(s).evaluate(op1, op2); - if (cond != OPT_ConditionOperand.UNKNOWN) { - Move.mutate(s, INT_MOVE, BooleanCmp.getResult(s), - (cond == OPT_ConditionOperand.TRUE) ? IC(1) : IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - } else { - // Canonicalize by switching operands and fliping code. - OPT_Operand tmp = BooleanCmp.getClearVal1(s); - BooleanCmp.setVal1(s, BooleanCmp.getClearVal2(s)); - BooleanCmp.setVal2(s, tmp); - BooleanCmp.getCond(s).flipOperands(); - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect booleanCmpAddr(OPT_Instruction s) { - if (CF_ADDR) { - OPT_Operand op1 = BooleanCmp.getVal1(s); - OPT_Operand op2 = BooleanCmp.getVal2(s); - if (op1.isConstant()) { - if (op2.isConstant()) { - // BOTH CONSTANTS: FOLD - int cond = BooleanCmp.getCond(s).evaluate(op1, op2); - if (cond != OPT_ConditionOperand.UNKNOWN) { - Move.mutate(s, REF_MOVE, BooleanCmp.getResult(s), - (cond == OPT_ConditionOperand.TRUE) ? IC(1) : IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - } else { - // Canonicalize by switching operands and fliping code. - OPT_Operand tmp = BooleanCmp.getClearVal1(s); - BooleanCmp.setVal1(s, BooleanCmp.getClearVal2(s)); - BooleanCmp.setVal2(s, tmp); - BooleanCmp.getCond(s).flipOperands(); - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect booleanCmp2IntOr(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op1 = BooleanCmp2.getVal1(s); - OPT_Operand op2 = BooleanCmp2.getVal2(s); - if (op1.isConstant()) { - if (op2.isConstant()) { - // 1st 2 operands are constants, can fold if result is true - int cond1 = BooleanCmp2.getCond1(s).evaluate(op1, op2); - if (cond1 == OPT_ConditionOperand.TRUE) { - Move.mutate(s, REF_MOVE, BooleanCmp2.getResult(s), IC(1)); - return DefUseEffect.MOVE_FOLDED; - } else if (cond1 == OPT_ConditionOperand.FALSE) { - BooleanCmp.mutate(s, BOOLEAN_CMP_INT, BooleanCmp2.getResult(s), - BooleanCmp2.getVal3(s), BooleanCmp2.getVal4(s), BooleanCmp2 - .getCond2(s), BooleanCmp2.getBranchProfile2(s)); - DefUseEffect result = booleanCmpInt(s); - return (result == DefUseEffect.UNCHANGED) ? DefUseEffect.REDUCED - : result; - } - } - } - OPT_Operand op3 = BooleanCmp2.getVal3(s); - OPT_Operand op4 = BooleanCmp2.getVal4(s); - if (op3.isConstant()) { - if (op4.isConstant()) { - // 3rd and 4th operands are constants, can fold if result is true - int cond2 = BooleanCmp2.getCond1(s).evaluate(op3, op4); - if (cond2 == OPT_ConditionOperand.TRUE) { - Move.mutate(s, REF_MOVE, BooleanCmp2.getResult(s), IC(1)); - return DefUseEffect.MOVE_FOLDED; - } else if (cond2 == OPT_ConditionOperand.FALSE) { - BooleanCmp.mutate(s, BOOLEAN_CMP_INT, BooleanCmp2.getResult(s), - BooleanCmp2.getVal1(s), BooleanCmp2.getVal2(s), BooleanCmp2 - .getCond1(s), BooleanCmp2.getBranchProfile1(s)); - DefUseEffect result = booleanCmpInt(s); - return (result == DefUseEffect.UNCHANGED) ? DefUseEffect.REDUCED - : result; - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intAdd(OPT_Instruction s) { - if (CF_INT) { - canonicalizeCommutativeOperator(s); - OPT_Operand op2 = Binary.getVal2(s); - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - OPT_Operand op1 = Binary.getVal1(s); - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 + val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2 == 0) { - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.MOVE_REDUCED; - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intAnd(OPT_Instruction s) { - if (CF_INT) { - canonicalizeCommutativeOperator(s); - OPT_Operand op1 = Binary.getVal1(s); - OPT_Operand op2 = Binary.getVal2(s); - if (op1.similar(op2)) { - // THE SAME OPERAND: x & x == x - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return op1.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 & val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2 == 0) { // x & 0 == 0 - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - if (val2 == -1) { // x & -1 == x & 0xffffffff == x - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.MOVE_REDUCED; - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intDiv(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op1 = GuardedBinary.getVal1(s); - OPT_Operand op2 = GuardedBinary.getVal2(s); - if (op1.similar(op2)) { - // THE SAME OPERAND: x / x == 1 - Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(1)); - return DefUseEffect.MOVE_FOLDED; - } - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - if (val2 == 0) { - // TODO: This instruction is actually unreachable. - // There will be an INT_ZERO_CHECK - // guarding this instruction that will result in an - // ArithmeticException. We - // should probabbly just remove the INT_DIV as dead code. - return DefUseEffect.UNCHANGED; - } - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(val1 - / val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2 == 1) { // x / 1 == x; - Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), - GuardedBinary.getClearVal1(s)); - return DefUseEffect.MOVE_REDUCED; - } - // x / c == x >> (log c) if c is power of 2 - int power = PowerOf2(val2); - if (power != -1) { - Binary.mutate(s, INT_SHR, GuardedBinary.getClearResult(s), - GuardedBinary.getClearVal1(s), IC(power)); - return DefUseEffect.REDUCED; - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intMul(OPT_AbstractRegisterPool regpool, - OPT_Instruction s) { - if (CF_INT) { - canonicalizeCommutativeOperator(s); - OPT_Operand op2 = Binary.getVal2(s); - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - OPT_Operand op1 = Binary.getVal1(s); - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 * val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2 == -1) { // x * -1 == -x - Unary.mutate(s, INT_NEG, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.REDUCED; - } - if (val2 == 0) { // x * 0 == 0 - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - if (val2 == 1) { // x * 1 == x - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.MOVE_REDUCED; - } - // try to reduce x*c into shift and adds, but only if cost is cheap - if (s.getPrev() != null) { - // don't attempt to reduce if this instruction isn't - // part of a well-formed sequence - int cost = 0; - for (int i = 1; i < BITS_IN_INT; i++) { - if ((val2 & (1 << i)) != 0) { - // each 1 requires a shift and add - cost++; - } - } - if (cost < 5) { - // generate shift and adds - OPT_RegisterOperand val1Operand = Binary.getClearVal1(s) - .asRegister(); - OPT_RegisterOperand resultOperand = regpool.makeTempInt(); - OPT_Instruction move; - if ((val2 & 1) == 1) { - // result = val1 * 1 - move = Move.create(INT_MOVE, resultOperand, val1Operand); - } else { - // result = 0 - move = Move.create(INT_MOVE, resultOperand, IC(0)); - } - move.copyPosition(s); - s.insertBefore(move); - for (int i = 1; i < BITS_IN_INT; i++) { - if ((val2 & (1 << i)) != 0) { - OPT_RegisterOperand tempInt = regpool.makeTempInt(); - OPT_Instruction shift = Binary.create(INT_SHL, tempInt, - val1Operand.copyRO(), IC(i)); - shift.copyPosition(s); - s.insertBefore(shift); - OPT_Instruction add = Binary.create(INT_ADD, resultOperand - .copyRO(), resultOperand.copyRO(), tempInt.copyRO()); - add.copyPosition(s); - s.insertBefore(add); - } - } - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), resultOperand - .copyRO()); - return DefUseEffect.REDUCED; - } - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intNeg(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op = Unary.getVal(s); - if (op.isIntConstant()) { - // CONSTANT: FOLD - int val = op.asIntConstant().value; - Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(-val)); - return DefUseEffect.MOVE_FOLDED; - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intNot(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op = Unary.getVal(s); - if (op.isIntConstant()) { - // CONSTANT: FOLD - int val = op.asIntConstant().value; - Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(~val)); - return DefUseEffect.MOVE_FOLDED; - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intOr(OPT_Instruction s) { - if (CF_INT) { - canonicalizeCommutativeOperator(s); - OPT_Operand op1 = Binary.getVal1(s); - OPT_Operand op2 = Binary.getVal2(s); - if (op1.similar(op2)) { - // THE SAME OPERAND: x | x == x - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return op1.isConstant() ? DefUseEffect.MOVE_FOLDED - : DefUseEffect.MOVE_REDUCED; - } - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 | val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2 == -1) { // x | -1 == x | 0xffffffff == 0xffffffff == -1 - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1)); - return DefUseEffect.MOVE_FOLDED; - } - if (val2 == 0) { // x | 0 == x - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.MOVE_REDUCED; - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intRem(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op1 = GuardedBinary.getVal1(s); - OPT_Operand op2 = GuardedBinary.getVal2(s); - if (op1.similar(op2)) { - // THE SAME OPERAND: x % x == 0 - Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - if (val2 == 0) { - // TODO: This instruction is actually unreachable. - // There will be an INT_ZERO_CHECK - // guarding this instruction that will result in an - // ArithmeticException. We - // should probabbly just remove the INT_REM as dead code. - return DefUseEffect.UNCHANGED; - } - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(val1 - % val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if ((val2 == 1) || (val2 == -1)) { // x % 1 == 0 - Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intShl(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op2 = Binary.getVal2(s); - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - OPT_Operand op1 = Binary.getVal1(s); - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 << val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2 == 0) { // x << 0 == x - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.MOVE_REDUCED; - } - if (val2 >= BITS_IN_INT) { // x << 32 == 0 - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intShr(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op2 = Binary.getVal2(s); - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - OPT_Operand op1 = Binary.getVal1(s); - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 >> val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2 == 0) { // x >> 0 == x - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.MOVE_REDUCED; - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intSub(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op1 = Binary.getVal1(s); - OPT_Operand op2 = Binary.getVal2(s); - if (op1.similar(op2)) { - // THE SAME OPERAND: x - x == 0 - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 - val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2 == 0) { // x - 0 == x - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.MOVE_REDUCED; - } - // x - c = x + -c - // prefer adds, since some architectures have addi but not subi - Binary.mutate(s, INT_ADD, Binary.getClearResult(s), Binary - .getClearVal1(s), IC(-val2)); - return DefUseEffect.REDUCED; - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intUshr(OPT_Instruction s) { - if (CF_INT) { - OPT_Operand op2 = Binary.getVal2(s); - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - OPT_Operand op1 = Binary.getVal1(s); - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 >>> val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2 == 0) { // x >>> 0 == x - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.MOVE_REDUCED; - } - if (val2 >= BITS_IN_INT) { // x >>> 32 == 0 - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect intXor(OPT_Instruction s) { - if (CF_INT) { - canonicalizeCommutativeOperator(s); - OPT_Operand op1 = Binary.getVal1(s); - OPT_Operand op2 = Binary.getVal2(s); - if (op1.similar(op2)) { - // THE SAME OPERAND: x ^ x == 0 - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); - return DefUseEffect.MOVE_FOLDED; - } - if (op2.isIntConstant()) { - int val2 = op2.asIntConstant().value; - - if (op1.isIntConstant()) { - // BOTH CONSTANTS: FOLD - int val1 = op1.asIntConstant().value; - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 ^ val2)); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2 == -1) { // x ^ -1 == x ^ 0xffffffff = ~x - Unary.mutate(s, INT_NOT, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.REDUCED; - } - if (val2 == 0) { // x ^ 0 == x - Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary - .getClearVal1(s)); - return DefUseEffect.MOVE_REDUCED; - } - } - } - } - return DefUseEffect.UNCHANGED; - } - - private static DefUseEffect refAdd(OPT_Instruction s) { - if (CF_ADDR) { - canonicalizeCommutativeOperator(s); - OPT_Operand op2 = Binary.getVal2(s); - if (op2.isConstant() && !op2.isObjectConstant()) { - Address val2 = getAddressValue(op2); - OPT_Operand op1 = Binary.getVal1(s); - if (op1.isConstant() && !op1.isObjectConstant()) { - // BOTH CONSTANTS: FOLD - Address val1 = getAddressValue(op1); - Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.plus(val2 - .toWord().toOffset()))); - return DefUseEffect.MOVE_FOLDED; - } else { - // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS - if (val2.isZero()) { // x + 0 == x - if (op1.isIntLike()) { - ... [truncated message content] |
From: <mic...@us...> - 2007-08-06 10:19:14
|
Revision: 155 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=155&view=rev Author: michael_baer Date: 2007-08-06 02:37:44 -0700 (Mon, 06 Aug 2007) Log Message: ----------- Exchanged loop by system.arraycopy Modified Paths: -------------- src/org/binarytranslator/arch/x86/decoder/X86_FlagLaziness.java Modified: src/org/binarytranslator/arch/x86/decoder/X86_FlagLaziness.java =================================================================== --- src/org/binarytranslator/arch/x86/decoder/X86_FlagLaziness.java 2007-08-02 13:59:57 UTC (rev 154) +++ src/org/binarytranslator/arch/x86/decoder/X86_FlagLaziness.java 2007-08-06 09:37:44 UTC (rev 155) @@ -31,9 +31,7 @@ } X86_FlagLaziness(byte[] flagLaziness) { - for (int i = 0; i < this.flagLaziness.length; i++) { - this.flagLaziness[i] = flagLaziness[i]; - } + System.arraycopy(flagLaziness, 0, this.flagLaziness, 0, flagLaziness.length); } public Object clone() { @@ -91,9 +89,7 @@ Key(int pc, byte[] flagLaziness) { this.pc = pc; - for (int i = 0; i < flagLaziness.length; i++) { - this.flagLaziness[i] = flagLaziness[i]; - } + System.arraycopy(flagLaziness, 0, this.flagLaziness, 0, flagLaziness.length); } public String toString() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-02 13:59:59
|
Revision: 154 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=154&view=rev Author: michael_baer Date: 2007-08-02 06:59:57 -0700 (Thu, 02 Aug 2007) Log Message: ----------- - Corrected bug in staged emulation controller - added javadoc Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/generic/execution/InterpreterController.java src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java src/org/binarytranslator/generic/execution/StagedEmulationController.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-02 12:22:44 UTC (rev 153) +++ src/org/binarytranslator/DBT_Options.java 2007-08-02 13:59:57 UTC (rev 154) @@ -90,6 +90,9 @@ /** GDB stub port */ public static int gdbStubPort = 1234; + /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ + public static int minTraceValue = 20; + /** Print debug information during the translation of instructions. */ public static boolean debugTranslation = true; @@ -153,49 +156,52 @@ } /** Parses a single argument into the options class. */ - private static void parseSingleArgument(String arg, String value) { + private static void parseSingleArgument(String key, String value) { - if (!arg.startsWith("-X:dbt:")) { + if (!key.startsWith("-X:dbt:")) { throw new Error("Invalid argument. Argument prefix '-X:dbt:' expected."); } - arg = arg.substring(7); + key = key.substring(7); - if (arg.equalsIgnoreCase("debugInstr")) { + if (key.equalsIgnoreCase("debugInstr")) { debugInstr = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("debugRuntime")) { + } else if (key.equalsIgnoreCase("debugRuntime")) { debugRuntime = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("debugBranchResolution")) { + } else if (key.equalsIgnoreCase("debugBranchResolution")) { debugBranchResolution = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("debugMemory")) { + } else if (key.equalsIgnoreCase("debugMemory")) { debugMemory = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("debugSyscall")) { + } else if (key.equalsIgnoreCase("debugSyscall")) { debugSyscall = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("debugSyscallMore")) { + } else if (key.equalsIgnoreCase("debugSyscallMore")) { debugSyscallMore = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("instrOpt0")) { + } else if (key.equalsIgnoreCase("instrOpt0")) { instrOpt0 = Integer.parseInt(value); - } else if (arg.equalsIgnoreCase("instrOpt1")) { + } else if (key.equalsIgnoreCase("instrOpt1")) { instrOpt1 = Integer.parseInt(value); - } else if (arg.equalsIgnoreCase("instrOpt2")) { + } else if (key.equalsIgnoreCase("instrOpt2")) { instrOpt2 = Integer.parseInt(value); - } else if (arg.equalsIgnoreCase("singleInstrTranslation")) { + } else if (key.equalsIgnoreCase("singleInstrTranslation")) { singleInstrTranslation = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("resolveDirectBranchesFirst")) { + } else if (key.equalsIgnoreCase("resolveDirectBranchesFirst")) { resolveDirectBranchesFirst = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("gdbStub")) { + } else if (key.equalsIgnoreCase("gdbStub")) { gdbStub = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("gdbStubPort")) { + } else if (key.equalsIgnoreCase("gdbStubPort")) { gdbStubPort = Integer.parseInt(value); - } else if (arg.equalsIgnoreCase("controller")) { + } else if (key.equalsIgnoreCase("controller")) { executionController = ExecutionController.Type.valueOf(value); - } else if (arg.equalsIgnoreCase("loadProfile")) { - loadProfileFromFile = arg; - } else if (arg.equalsIgnoreCase("saveProfile")) { - saveProfileToFile = arg; + } else if (key.equalsIgnoreCase("loadProfile")) { + loadProfileFromFile = value; + } else if (key.equalsIgnoreCase("saveProfile")) { + saveProfileToFile = value; + } else if (key.equalsIgnoreCase("minTraceValue")) { + minTraceValue = Integer.parseInt(value); } + else { - throw new Error("Unknown DBT option: " + arg); + throw new Error("Unknown DBT option: " + key); } } Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-08-02 12:22:44 UTC (rev 153) +++ src/org/binarytranslator/Main.java 2007-08-02 13:59:57 UTC (rev 154) @@ -105,7 +105,7 @@ //on SUN's VM, only the interpreter has been tested if (DBT_Options.buildForSunVM) { - DBT_Options.executionController = ExecutionController.Type.PredecodingInterpreter; + DBT_Options.executionController = ExecutionController.Type.StagedEmulation; } //load a previously saved branch profile from file, if the user requested it Modified: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java 2007-08-02 12:22:44 UTC (rev 153) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-08-02 13:59:57 UTC (rev 154) @@ -1,9 +1,12 @@ package org.binarytranslator.generic.execution; -import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.os.process.ProcessSpace; +/** + * Implements straight-forward interpretation using the {@link Interpreter} + * and {@link Interpreter.Instruction} interfaces. + */ public class InterpreterController extends ExecutionController { public InterpreterController(ProcessSpace ps) { Modified: src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java 2007-08-02 12:22:44 UTC (rev 153) +++ src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java 2007-08-02 13:59:57 UTC (rev 154) @@ -3,6 +3,12 @@ import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.os.process.ProcessSpace; +/** + * Implements straight-forward interpretation using the {@link Interpreter} + * and {@link Interpreter.Instruction} interfaces. + * + * Additionally, this controller performs profiling during the interpretation. + */ public class ProfilingInterpreterController extends ExecutionController { public ProfilingInterpreterController(ProcessSpace ps) { Modified: src/org/binarytranslator/generic/execution/StagedEmulationController.java =================================================================== --- src/org/binarytranslator/generic/execution/StagedEmulationController.java 2007-08-02 12:22:44 UTC (rev 153) +++ src/org/binarytranslator/generic/execution/StagedEmulationController.java 2007-08-02 13:59:57 UTC (rev 154) @@ -13,24 +13,46 @@ import org.binarytranslator.vmInterface.DynamicCodeRunner; import org.jikesrvm.ArchitectureSpecific.VM_CodeArray; +/** + * This controller implements staged emulation, i.e. switching between interpretation + * and translation dynamically. + * + */ public class StagedEmulationController extends ExecutionController { - private final class Trace { - public final List<Interpreter.Instruction> instructions; + /** Represents a dynamic basic block of instructions. */ + private final class DynamicBasicBlock { + /** The instructions within this dynamic basic block. */ + public List<Interpreter.Instruction> instructions; + + /** A value describing how "hot" the basic block is, i.e. how often it has been executed.*/ public int value; + + /** A handle to the compiled version of this dynamic basic block or null, if there is none. */ public DBT_Trace compiledTrace; - public Trace(List<Interpreter.Instruction> instructions) { + public DynamicBasicBlock(List<Interpreter.Instruction> instructions) { this.instructions = instructions; value = 0; } } - private final HashMap<Integer, Trace> traceCache = new HashMap<Integer, Trace>(); + /** Maps a dynamic basic block to the address of the first instruction within that block. */ + private final HashMap<Integer, DynamicBasicBlock> traceCache = new HashMap<Integer, DynamicBasicBlock>(); + + /** The interpreter that is used to perform the actual execution of single instructions. */ private final Interpreter interpreter; - private Trace getTrace(int pc) { - Trace cachedTrace = traceCache.get(pc); + /** + * Returns the dynamic basic block starting at address <code>pc</code>. + * + * @param pc + * The starting address of a dynamic basic block. + * @return + * An object representation of the dynamic basic block. + */ + private DynamicBasicBlock getBlock(int pc) { + DynamicBasicBlock cachedTrace = traceCache.get(pc); if (cachedTrace != null) return cachedTrace; @@ -46,7 +68,7 @@ //is the successor to this instruction known? if (pc == -1) { //No, so stop and create a trace from the decoded instructions - Trace newTrace = new Trace(instructions); + DynamicBasicBlock newTrace = new DynamicBasicBlock(instructions); if (instructions.size() > 3) { //add this trace to the trace cache, if it contains enough instructions @@ -58,17 +80,34 @@ } } - private void compileTrace(Trace trace, int pc) { + /** + * Compiles a dynamic basic block into a trace. + * + * @param trace + * The dynamic basic block to compile. + * @param pc + * The address of the first instruction within the dynamic basic block. + */ + private void compileBlock(DynamicBasicBlock trace, int pc) { if (DBT.VerifyAssertions) DBT._assert(trace.compiledTrace == null); trace.compiledTrace = new DBT_Trace(ps, pc); trace.compiledTrace.compile(); + trace.instructions = null; } - private void executeTrace(Trace trace, int pc) { + /** + * Executes the instructions within a dynamic basic block. + * + * @param trace + * The dynamic basic block whose instructions shall be executed. + * @param pc + * The address of the first instruction within that dynamic basic block. + */ + private void executeBlock(DynamicBasicBlock trace, int pc) { //check if the trace is being executed very frequently... - if (trace.value > 20) { + if (trace.value > DBT_Options.minTraceValue) { if (DBT_Options.debugTranslation) System.out.println("Switching to interpretation at address 0x" + Integer.toHexString(pc)); @@ -76,13 +115,18 @@ //yes, so we should rather try to execute a translated version if (trace.compiledTrace == null) { //compile the trace, if necessary - compileTrace(trace, pc); + compileBlock(trace, pc); if (DBT.VerifyAssertions) DBT._assert(trace.compiledTrace != null); } //execute the trace VM_CodeArray code = trace.compiledTrace.getCurrentCompiledMethod().getEntryCodeArray(); ps.setCurrentInstructionAddress(DynamicCodeRunner.invokeCode(code, ps)); + + if (DBT_Options.debugTranslation) + System.out.println("Returning from interpretation at 0x" + Integer.toHexString(ps.getCurrentInstructionAddress())); + + return; } else { trace.value += trace.instructions.size(); @@ -102,6 +146,7 @@ } } + /** Default constructor */ public StagedEmulationController(ProcessSpace ps) { super(ps); interpreter = ps.createInterpreter(); @@ -113,8 +158,8 @@ while (!ps.finished) { - Trace trace = getTrace(pc); - executeTrace(trace, pc); + DynamicBasicBlock trace = getBlock(pc); + executeBlock(trace, pc); pc = ps.getCurrentInstructionAddress(); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-02 12:22:43
|
Revision: 153 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=153&view=rev Author: michael_baer Date: 2007-08-02 05:22:44 -0700 (Thu, 02 Aug 2007) Log Message: ----------- - Allowing to load/save branch profiles - Added generic profiling to the Interpreter - Added support for staged emulation Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java src/org/binarytranslator/generic/branchprofile/BranchProfile.java src/org/binarytranslator/generic/branchprofile/CallAndReturnAddress.java src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java src/org/binarytranslator/generic/execution/ExecutionController.java src/org/binarytranslator/generic/execution/InterpreterController.java src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java Added Paths: ----------- src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java src/org/binarytranslator/generic/execution/StagedEmulationController.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/DBT_Options.java 2007-08-02 12:22:44 UTC (rev 153) @@ -49,7 +49,13 @@ /** Determines how the program will be run (i.e. interpreted, translated etc.) */ public static ExecutionController.Type executionController = ExecutionController.Type.Translator; + + /** A filename to which the runtime profiling information shall be saved. */ + public static String saveProfileToFile = null; + /** A filename from which the runtime profiling information shall be loaded. */ + public static String loadProfileFromFile = null; + /** * Favour backward branch optimization. Translate backward branch addresses * before the next instructions (this is the manner of the 601's branch @@ -183,7 +189,12 @@ gdbStubPort = Integer.parseInt(value); } else if (arg.equalsIgnoreCase("controller")) { executionController = ExecutionController.Type.valueOf(value); - } else { + } else if (arg.equalsIgnoreCase("loadProfile")) { + loadProfileFromFile = arg; + } else if (arg.equalsIgnoreCase("saveProfile")) { + saveProfileToFile = arg; + } + else { throw new Error("Unknown DBT option: " + arg); } } Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/Main.java 2007-08-02 12:22:44 UTC (rev 153) @@ -9,12 +9,14 @@ package org.binarytranslator; import java.io.File; - import org.binarytranslator.generic.execution.PredecodingThreadedInterpreter; import org.binarytranslator.generic.execution.DynamicTranslationController; import org.binarytranslator.generic.execution.ExecutionController; import org.binarytranslator.generic.execution.GdbController; import org.binarytranslator.generic.execution.InterpreterController; +import org.binarytranslator.generic.execution.ProfilingInterpreterController; +import org.binarytranslator.generic.execution.ProfilingPredecodingInterpreter; +import org.binarytranslator.generic.execution.StagedEmulationController; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; @@ -93,10 +95,6 @@ System.err.println("Error accesing file: " + args[0] + ". " + e.getMessage()); return; } - /*catch (Error e) { - System.err.println(e.getMessage()); - return; - }*/ report("Sucessfully created process."); @@ -108,20 +106,35 @@ //on SUN's VM, only the interpreter has been tested if (DBT_Options.buildForSunVM) { DBT_Options.executionController = ExecutionController.Type.PredecodingInterpreter; - } + //load a previously saved branch profile from file, if the user requested it + try { + if (DBT_Options.loadProfileFromFile != null) + ps.branchInfo.loadFromXML(DBT_Options.loadProfileFromFile); + } catch (Exception e) { + System.err.println("Error loading branch profile from: " + DBT_Options.loadProfileFromFile); + e.printStackTrace(); + return; + } + //Create an execution controller and pass execution on to it ExecutionController controller = null; switch (DBT_Options.executionController) { + case StagedEmulation: + controller = new StagedEmulationController(ps); + break; + case PredecodingInterpreter: - controller = new PredecodingThreadedInterpreter(ps); //new PredecodingThreadedInterpreter(ps); - break; + controller = DBT_Options.profileDuringInterpretation ? + new ProfilingPredecodingInterpreter(ps) : new PredecodingThreadedInterpreter(ps); + break; case Interpreter: - controller = new InterpreterController(ps); + controller = DBT_Options.profileDuringInterpretation ? + new ProfilingInterpreterController(ps) : new InterpreterController(ps); break; case Translator: @@ -143,10 +156,11 @@ public static void onExit(int exitcode) { System.out.println("\nProgram has finished. Exitcode: " + exitcode); - /*try { - //ps.branchInfo.saveAsXML("/tmp/profile.xml"); - } catch (IOException e) { + try { + if (DBT_Options.saveProfileToFile != null) + ps.branchInfo.saveAsXML(DBT_Options.saveProfileToFile); + } catch (Exception e) { e.printStackTrace(); - }*/ + } } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-08-02 12:22:44 UTC (rev 153) @@ -20,7 +20,6 @@ import org.binarytranslator.arch.arm.decoder.ARM_Instructions.UndefinedInstruction; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.Instruction.Condition; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; -import org.binarytranslator.generic.decoder.DisassembledInstruction; import org.binarytranslator.generic.decoder.Disassembler; /** Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-08-02 12:22:44 UTC (rev 153) @@ -385,7 +385,7 @@ this.conditionalInstruction = i; conditionTrueSuccessor = conditionalInstruction.getSuccessor(pc); - boolean inThumbMode = (pc & 1) == 0; + boolean inThumbMode = (pc & 1) == 1; if (conditionTrueSuccessor == pc + 4 && !inThumbMode) successorInstruction = conditionTrueSuccessor; //ARM may have conditional instruction that are not jumps Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-02 12:22:44 UTC (rev 153) @@ -58,11 +58,10 @@ public int translateInstruction(int pc, ARM_Laziness lazy) { this.pc = pc; this.lazy = lazy; - boolean thumb = (pc & 1) != 0; int instruction; try { - if (thumb) + if (inThumb()) instruction = ps.memory.loadInstruction16(pc & 0xFFFFFFFE); else instruction = ps.memory.loadInstruction32(pc); @@ -88,7 +87,7 @@ } ARM_Instruction instr; - if (thumb) + if (inThumb()) instr = ARM_InstructionDecoder.Thumb.decode((short)instruction, translatorFactory); else instr = ARM_InstructionDecoder.ARM32.decode(instruction, translatorFactory); @@ -756,79 +755,99 @@ arm2ir.getCurrentBlock().insertOut(nextInstruction); arm2ir.getCurrentBlock().insertOut(condBlock); + //Query the branch profile to get the probability that this instruction is going to get executed + float skipProbability = ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); + OPT_BranchProfileOperand profileOperand; + + if (skipProbability == -1 || skipProbability == 0.5f) { + profileOperand = new OPT_BranchProfileOperand(); + } + else if (skipProbability > 0.8f) { + profileOperand = OPT_BranchProfileOperand.always(); + } + else if (skipProbability > 0.5f) { + profileOperand = OPT_BranchProfileOperand.likely(); + } + else if (skipProbability < 0.2f) { + profileOperand = OPT_BranchProfileOperand.never(); + } + else { + profileOperand = OPT_BranchProfileOperand.unlikely(); + } + switch (condition) { case AL: throw new RuntimeException("ARM32 instructions with a condition of AL (always) should not be decorated with a ConditionalDecorator."); case CC: //return !regs.isCarrySet(); - translateCondition(nextInstruction, arm2ir.getCarryFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getCarryFlag(), OPT_ConditionOperand.NOT_EQUAL()); break; case CS: //return regs.isCarrySet(); - translateCondition(nextInstruction, arm2ir.getCarryFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getCarryFlag(), OPT_ConditionOperand.EQUAL()); break; case EQ: //return regs.isZeroSet(); - translateCondition(nextInstruction, arm2ir.getZeroFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getZeroFlag(), OPT_ConditionOperand.EQUAL()); break; case GE: //return regs.isNegativeSet() == regs.isOverflowSet(); - translateCondition(nextInstruction, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL(), arm2ir.getOverflowFlag()); + translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL(), arm2ir.getOverflowFlag()); break; case GT: - translateCondition_GT(nextInstruction); + translateCondition_GT(nextInstruction, profileOperand); break; case HI: - translateCondition_HI(nextInstruction); + translateCondition_HI(nextInstruction, profileOperand); break; case LE: - translateCondition_LE(nextInstruction); + translateCondition_LE(nextInstruction, profileOperand); break; case LS: - translateCondition_LS(nextInstruction, condBlock); + translateCondition_LS(nextInstruction, profileOperand, condBlock); break; case LT: //return regs.isNegativeSet() != regs.isOverflowSet(); - translateCondition(nextInstruction, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.getOverflowFlag()); + translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.getOverflowFlag()); break; case MI: //return regs.isNegativeSet(); - translateCondition(nextInstruction, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL()); break; case NE: //return !regs.isZeroSet(); - translateCondition(nextInstruction, arm2ir.getZeroFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getZeroFlag(), OPT_ConditionOperand.NOT_EQUAL()); break; case NV: //never execute this instruction - translateCondition(nextInstruction, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction, profileOperand, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL()); break; case PL: //return !regs.isNegativeSet(); - translateCondition(nextInstruction, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL()); break; case VC: //return !regs.isOverflowSet(); - translateCondition(nextInstruction, arm2ir.getOverflowFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getOverflowFlag(), OPT_ConditionOperand.NOT_EQUAL()); break; case VS: //return regs.isOverflowSet(); - translateCondition(nextInstruction, arm2ir.getOverflowFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getOverflowFlag(), OPT_ConditionOperand.EQUAL()); break; default: @@ -839,17 +858,17 @@ conditionalInstruction.translate(); } - private void translateCondition(OPT_BasicBlock nextInstruction, OPT_Operand operand, OPT_ConditionOperand condition) { - translateCondition(nextInstruction, operand, condition, new OPT_IntConstantOperand(1)); + private void translateCondition(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_Operand operand, OPT_ConditionOperand condition) { + translateCondition(nextInstruction, skipProbability, operand, condition, new OPT_IntConstantOperand(1)); } - private void translateCondition(OPT_BasicBlock nextInstruction, OPT_Operand lhs, OPT_ConditionOperand condition, OPT_Operand rhs) { + private void translateCondition(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_Operand lhs, OPT_ConditionOperand condition, OPT_Operand rhs) { condition = condition.flipCode(); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), lhs, rhs, condition, nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), lhs, rhs, condition, nextInstruction.makeJumpTarget(), skipProbability)); } - private void translateCondition_HI(OPT_BasicBlock nextInstruction) { + private void translateCondition_HI(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isCarrySet() && !regs.isZeroSet(); OPT_Operand carry = arm2ir.getCarryFlag(); OPT_Operand zero = arm2ir.getZeroFlag(); @@ -858,10 +877,10 @@ arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, carry, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); } - private void translateCondition_LS(OPT_BasicBlock nextInstruction, OPT_BasicBlock actualInstruction) { + private void translateCondition_LS(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_BasicBlock actualInstruction) { //return !regs.isCarrySet() || regs.isZeroSet(); OPT_Operand carry = arm2ir.getCarryFlag(); OPT_Operand zero = arm2ir.getZeroFlag(); @@ -869,7 +888,7 @@ OPT_RegisterOperand result = arm2ir.getTempInt(0); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, carry, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); /* cond1.deleteNormalOut(); cond1.insertOut(cond2); @@ -885,7 +904,7 @@ cond2.insertOut(actualInstruction);*/ } - private void translateCondition_GT(OPT_BasicBlock nextInstruction) { + private void translateCondition_GT(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return (regs.isNegativeSet() == regs.isOverflowSet()) && !regs.isZeroSet(); OPT_Operand negative = arm2ir.getNegativeFlag(); OPT_Operand overflow = arm2ir.getOverflowFlag(); @@ -895,10 +914,10 @@ arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, negative, overflow, OPT_ConditionOperand.NOT_EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); } - private void translateCondition_LE(OPT_BasicBlock nextInstruction) { + private void translateCondition_LE(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isZeroSet() || (regs.isNegativeSet() != regs.isOverflowSet()); OPT_Operand negative = arm2ir.getNegativeFlag(); OPT_Operand overflow = arm2ir.getOverflowFlag(); @@ -908,7 +927,7 @@ arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, negative, overflow, OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); } @Override Modified: src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-02 12:22:44 UTC (rev 153) @@ -13,6 +13,7 @@ import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; +import org.binarytranslator.Main; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; /** @@ -691,6 +692,7 @@ @Override public void execute() { ps.finished = true; + Main.onExit(0); } } Modified: src/org/binarytranslator/generic/branchprofile/BranchProfile.java =================================================================== --- src/org/binarytranslator/generic/branchprofile/BranchProfile.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/branchprofile/BranchProfile.java 2007-08-02 12:22:44 UTC (rev 153) @@ -121,7 +121,7 @@ throw new IOException("File is not a valid XML branch profile."); int targetAddress = Integer.parseInt(((Element)target).getAttribute("address")); - int branchCount = Integer.parseInt(((Element)target).getAttribute("address")); + int branchCount = Integer.parseInt(((Element)target).getAttribute("branchCount")); targetsAndFrequencies.put(targetAddress, branchCount); } @@ -131,8 +131,6 @@ public void toXML(Document doc, Element parentNode) { Element branchInfo = parentNode; - Element targets = doc.createElement("targets"); - for (Entry<Integer, Integer> branchTarget : destinationsAndFrequencies.entrySet()) { int targetAddress = branchTarget.getKey(); int branchCount = branchTarget.getValue(); @@ -142,8 +140,6 @@ branchTargetElement.setAttribute("address", Integer.toString(targetAddress)); branchTargetElement.setAttribute("branchCount", Integer.toString(branchCount)); } - - branchInfo.appendChild(targets); } } @@ -243,6 +239,33 @@ branchSites.put(origin, branch); } } + + /** + * Returns the probability of a branch from <code>origin</code> to <code>target</code>. + * + * @param origin + * The address at which the branch is taking place. + * @param target + * The address to which the branch is taking place. + * @return + * The probability of the branch as a value between 0 and 1. The function returns -1, if the probability + * cannot be estimated. + */ + public float getBranchProbability(int origin, int target) { + BranchInformation branch = branchSites.get(origin); + + if (branch == null || branch.executionCount == 0) { + return -1f; + } + + Integer branchesToTarget = branch.getTargetsAndFrequencies().get(target); + + if (branchesToTarget == null) { + return 0f; + } + + return branchesToTarget / (float)branch.executionCount; + } /** * Given an address within a procedure, returns the (most likely) procedure @@ -271,7 +294,15 @@ * The address to which it took place. */ public void profileBranch(int origin, int target) { - throw new RuntimeException("Not yet implemented."); + + BranchInformation branch = branchSites.get(origin); + + if (branch == null) { + branch = new BranchInformation(); + branchSites.put(origin, branch); + } + + branch.profile(target); } /** @@ -288,8 +319,21 @@ return (branch == null) ? null : branch.getTargets(); } + /** + * Loads a branch profile from a file. + * + * @param filename + * The name of the file that the branch profile is loaded from. + * @throws IOException + * An exception that is thrown if an error occurs reading that file. + */ public void loadFromXML(String filename) throws IOException { + //clear previous profile data + procedures.clear(); + branchSites.clear(); + + //create a XML document builder and an XML document DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); Document doc; try { @@ -303,34 +347,54 @@ if (DBT.VerifyAssertions) DBT._assert(doc != null); + //Check the root-name of the document Element root = doc.getDocumentElement(); - if (!root.getNodeName().equals("branch-profile")) throw new IOException("File is not a valid XML branch profile."); - Node branches = null; - + //interate over the main document, parsing the different sections for (int i = 0; i < root.getChildNodes().getLength(); i++) { - Node node = root.getChildNodes().item(0); + Node node = root.getChildNodes().item(i); + String nodeName = node.getNodeName(); - if (node.getNodeName().equals("branches")) { - branches = node; - break; + if (node.getNodeType() != Node.ELEMENT_NODE) { + continue; } - } - - if (branches == null) - throw new IOException("File is not a valid XML branch profile."); - - for (int i = 0; i < branches.getChildNodes().getLength(); i++) { - Node siteNode = branches.getChildNodes().item(i); - if (!siteNode.getNodeName().equals("origin") || siteNode.getNodeType() != Node.ELEMENT_NODE) - throw new IOException("File is not a valid XML branch profile."); + if (nodeName.equals("branches")) { - int address = Integer.parseInt(((Element)siteNode).getAttribute("address")); - BranchInformation branchInfo = BranchInformation.fromXML((Element)siteNode); - branchSites.put(address, branchInfo); + //this is the section which contains the branch information. + for (int n = 0; n < node.getChildNodes().getLength(); n++) { + Node branchNode = node.getChildNodes().item(n); + + if (branchNode.getNodeType() != Node.ELEMENT_NODE) + continue; + + if (!branchNode.getNodeName().equals("branch")) + throw new IOException("File is not a valid XML branch profile."); + + int address = Integer.parseInt(((Element)branchNode).getAttribute("address")); + BranchInformation branchInfo = BranchInformation.fromXML((Element)branchNode); + branchSites.put(address, branchInfo); + } + } + else + if (nodeName.equals("procedures")) { + + //this is the section with procedure information + for (int n = 0; n < node.getChildNodes().getLength(); n++) { + Node procedureInfo = node.getChildNodes().item(n); + + if (procedureInfo.getNodeType() != Node.ELEMENT_NODE) + continue; + + ProcedureInformation pi = ProcedureInformation.fromXML((Element)procedureInfo); + procedures.put(pi.getEntryAddress(), pi); + } + } + else { + throw new IOException("This is not a valid XML branch profile."); + } } } @@ -387,6 +451,15 @@ branchInfo.toXML(doc, branchSiteElement); } + Element proceduresElement = doc.createElement("procedures"); + root.appendChild(proceduresElement); + + for (ProcedureInformation procedure : procedures.values()) { + Element procedureElement = doc.createElement("procedure"); + proceduresElement.appendChild(procedureElement); + procedure.toXML(doc, procedureElement); + } + //Output the resulting XML document TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer; @@ -395,6 +468,7 @@ DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult(outputStream); transformer.transform(source, result); + outputStream.close(); } catch (Exception e) { e.printStackTrace(); Modified: src/org/binarytranslator/generic/branchprofile/CallAndReturnAddress.java =================================================================== --- src/org/binarytranslator/generic/branchprofile/CallAndReturnAddress.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/branchprofile/CallAndReturnAddress.java 2007-08-02 12:22:44 UTC (rev 153) @@ -12,14 +12,11 @@ * Object for recording a call site and its corresponding return address */ class CallAndReturnAddress { - /** - * Call site address - */ + + /** The address at which the call is taking place.*/ private int callSite; - /** - * Return address - */ + /** The address to which the call shall return. */ private int returnAddress; /** @@ -35,24 +32,29 @@ this.returnAddress = returnAddress; } - /** - * Get call site address - */ + /** Get call site address */ int getCallSite() { return callSite; } - /** - * Get return address - */ + /** Get return address */ int getReturnAddress() { return returnAddress; } + + @Override + public int hashCode() { + return callSite; + } - /** - * Are two call sites the same? - */ + @Override public boolean equals(Object obj) { - return ((CallAndReturnAddress) obj).callSite == callSite; + + if (!(obj instanceof CallAndReturnAddress)) { + return false; + } + + CallAndReturnAddress other = ((CallAndReturnAddress) obj); + return other.callSite == callSite && other.returnAddress == returnAddress; } } Modified: src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java =================================================================== --- src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java 2007-08-02 12:22:44 UTC (rev 153) @@ -19,20 +19,15 @@ * Objects capturing information about what looks like a method */ class ProcedureInformation { - /** - * Entry point to the procedure - */ + + /** Entry point to the procedure */ private final int entry; - /** - * Set of locations that call the procedure and the corressponding return - * address - */ + /** Set of locations that call the procedure and the corressponding return + * address. */ private HashSet<CallAndReturnAddress> callSitesAndReturnAddresses; - /** - * Set of locations within the procedure that return - */ + /** Set of locations within the procedure that return */ private HashSet<Integer> returnSites; /** @@ -50,8 +45,15 @@ } } - private ProcedureInformation(int entry) { + /** + * Constructor + * + * @param entry + * starting address of the procedure + */ + public ProcedureInformation(int entry) { this.entry = entry; + callSitesAndReturnAddresses = new HashSet<CallAndReturnAddress>(); } /** @@ -64,23 +66,32 @@ * @param returnAddress * the corresponding return address */ - ProcedureInformation(int entry, int callSite, int returnAddress) { - this.entry = entry; - callSitesAndReturnAddresses = new HashSet<CallAndReturnAddress>(); + public ProcedureInformation(int entry, int callSite, int returnAddress) { + this(entry); + callSitesAndReturnAddresses.add(new CallAndReturnAddress(callSite, returnAddress)); } + + /** + * Returns the address at which this procedure starts. + * @return + * The address at which the procedure starts. + */ + public int getEntryAddress() { + return entry; + } /** * Register a call (branch and link) instruction * - * @param pc - * the address of the branch instruction + * @param atAddress + * the address of the call instruction * @param ret * the address that will be returned to */ - public void registerCall(int pc, int ret) { - CallAndReturnAddress call_tuple = new CallAndReturnAddress(pc, ret); + public void registerCall(int atAddress, int ret) { + CallAndReturnAddress call_tuple = new CallAndReturnAddress(atAddress, ret); if (!callSitesAndReturnAddresses.contains(call_tuple)) { callSitesAndReturnAddresses.add(call_tuple); } @@ -89,15 +100,15 @@ /** * Register a return (branch to link register) instruction * - * @param pc + * @param atAddress * the address of the branch instruction */ - public void registerReturn(int pc) { + public void registerReturn(int atAddress) { if (returnSites == null) { returnSites = new HashSet<Integer>(); } - returnSites.add(new Integer(pc)); + returnSites.add(new Integer(atAddress)); } /** @@ -121,13 +132,17 @@ } procedure.appendChild(callSites); - Element returnSites = doc.createElement("returnsites"); - for (Integer returnSite : this.returnSites) { - Element returnSiteNode = doc.createElement("return"); - returnSiteNode.setAttribute("at", returnSite.toString()); - returnSites.appendChild(returnSiteNode); + if (returnSites != null) { + Element returnSitesElement = doc.createElement("returnsites"); + procedure.appendChild(returnSitesElement); + + for (Integer returnSite : returnSites) { + Element returnSiteNode = doc.createElement("return"); + returnSiteNode.setAttribute("at", returnSite.toString()); + returnSitesElement.appendChild(returnSiteNode); + } + } - procedure.appendChild(returnSites); } /** @@ -156,7 +171,7 @@ if (callsite.getNodeType() != Node.ELEMENT_NODE) continue; - if (callsite.getNodeName().equals("call")) + if (!callsite.getNodeName().equals("call")) throw new Error("The given XML node is not a valid ProcedureInformation entity."); int callFrom = Integer.parseInt(((Element)callsite).getAttribute("from")); @@ -166,6 +181,9 @@ } } else if (childNode.getNodeName().equals("returnsites")) { + + pi.returnSites = new HashSet<Integer>(); + //parse return sites for (int n = 0; n < childNode.getChildNodes().getLength(); n++) { Node callsite = childNode.getChildNodes().item(n); @@ -174,7 +192,7 @@ if (callsite.getNodeType() != Node.ELEMENT_NODE) continue; - if (callsite.getNodeName().equals("return")) + if (!callsite.getNodeName().equals("return")) throw new Error("The given XML node is not a valid ProcedureInformation entity."); int returnAt = Integer.parseInt(((Element)callsite).getAttribute("at")); Modified: src/org/binarytranslator/generic/execution/ExecutionController.java =================================================================== --- src/org/binarytranslator/generic/execution/ExecutionController.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/execution/ExecutionController.java 2007-08-02 12:22:44 UTC (rev 153) @@ -9,6 +9,7 @@ Translator, Interpreter, PredecodingInterpreter, + StagedEmulation, GDB } Modified: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-08-02 12:22:44 UTC (rev 153) @@ -13,23 +13,16 @@ @Override public void run() { Interpreter interpreter = ps.createInterpreter(); - int pc = ps.getCurrentInstructionAddress(); while (!ps.finished) { - Interpreter.Instruction instruction = interpreter.decode(pc); - //System.out.println(String.format("[0x%x] %s", pc, instruction.toString())); - + Interpreter.Instruction instruction = interpreter.decode(pc); instruction.execute(); - //System.out.println(ps.toString()); int nextInstruction = instruction.getSuccessor(pc); if (nextInstruction == -1) { nextInstruction = ps.getCurrentInstructionAddress(); - - if (DBT_Options.profileDuringInterpretation) - ps.branchInfo.profileBranch(pc, ps.getCurrentInstructionAddress()); } else { ps.setCurrentInstructionAddress(nextInstruction); Modified: src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java =================================================================== --- src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java 2007-08-02 12:22:44 UTC (rev 153) @@ -8,10 +8,33 @@ import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.os.process.ProcessSpace; +/** + * Execution controller that implements predecoding, threaded interpretation. + * + */ public class PredecodingThreadedInterpreter extends ExecutionController { + /** The controller keeps a cache of commonly used code traces. Each trace is essentially a dynamic basic block. + * This HashMap maps the address of a trace's first instruction to its dynamic basic block. */ private final HashMap<Integer, List<Interpreter.Instruction>> traceCache = new HashMap<Integer, List<Interpreter.Instruction>>(); + + /** The interpreter that is used to perform the actual execution of single instructions. */ private final Interpreter interpreter; + /** Default constructor. */ + public PredecodingThreadedInterpreter(ProcessSpace ps) { + super(ps); + interpreter = ps.createInterpreter(); + } + + /** + * Returns the dynamic basic block of instructions, starting it at address <code>pc</code>. + * This function also manages the trace cache ({@link #traceCache}). + * + * @param pc + * The address at which the dynamic basic block starts. + * @return + * A list of instructions that form the dynamic basic block. + */ private List<Interpreter.Instruction> getTrace(int pc) { List<Interpreter.Instruction> cachedTrace = traceCache.get(pc); @@ -42,6 +65,14 @@ return newTrace; } + /** + * Executes a list of instructions. It is assumed that the first instruction starts at address <code>pc</code>. + * + * @param trace + * The list of instructions that is to be executed. + * @param pc + * The address of the first instruction. + */ protected void executeTrace(List<Interpreter.Instruction> trace, int pc) { Iterator<Interpreter.Instruction> instructions = trace.iterator(); @@ -57,11 +88,6 @@ break; } } - - public PredecodingThreadedInterpreter(ProcessSpace ps) { - super(ps); - interpreter = ps.createInterpreter(); - } @Override public final void run() { Added: src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java (rev 0) +++ src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java 2007-08-02 12:22:44 UTC (rev 153) @@ -0,0 +1,36 @@ +package org.binarytranslator.generic.execution; + +import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.os.process.ProcessSpace; + +public class ProfilingInterpreterController extends ExecutionController { + + public ProfilingInterpreterController(ProcessSpace ps) { + super(ps); + } + + @Override + public void run() { + Interpreter interpreter = ps.createInterpreter(); + + int pc = ps.getCurrentInstructionAddress(); + + while (!ps.finished) { + Interpreter.Instruction instruction = interpreter.decode(pc); + + instruction.execute(); + int nextInstruction = instruction.getSuccessor(pc); + + if (nextInstruction == -1) { + nextInstruction = ps.getCurrentInstructionAddress(); + ps.branchInfo.profileBranch(pc, ps.getCurrentInstructionAddress()); + } + else { + ps.setCurrentInstructionAddress(nextInstruction); + } + + pc = nextInstruction; + } + } + +} Added: src/org/binarytranslator/generic/execution/StagedEmulationController.java =================================================================== --- src/org/binarytranslator/generic/execution/StagedEmulationController.java (rev 0) +++ src/org/binarytranslator/generic/execution/StagedEmulationController.java 2007-08-02 12:22:44 UTC (rev 153) @@ -0,0 +1,121 @@ +package org.binarytranslator.generic.execution; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.os.process.ProcessSpace; +import org.binarytranslator.vmInterface.DBT_Trace; +import org.binarytranslator.vmInterface.DynamicCodeRunner; +import org.jikesrvm.ArchitectureSpecific.VM_CodeArray; + +public class StagedEmulationController extends ExecutionController { + + private final class Trace { + public final List<Interpreter.Instruction> instructions; + public int value; + public DBT_Trace compiledTrace; + + public Trace(List<Interpreter.Instruction> instructions) { + this.instructions = instructions; + value = 0; + } + } + + private final HashMap<Integer, Trace> traceCache = new HashMap<Integer, Trace>(); + private final Interpreter interpreter; + + private Trace getTrace(int pc) { + Trace cachedTrace = traceCache.get(pc); + + if (cachedTrace != null) + return cachedTrace; + + int traceStart = pc; + ArrayList<Interpreter.Instruction> instructions = new ArrayList<Interpreter.Instruction>(5); + + while (true) { + Interpreter.Instruction instruction = interpreter.decode(pc); + pc = instruction.getSuccessor(pc); + instructions.add(instruction); + + //is the successor to this instruction known? + if (pc == -1) { + //No, so stop and create a trace from the decoded instructions + Trace newTrace = new Trace(instructions); + + if (instructions.size() > 3) { + //add this trace to the trace cache, if it contains enough instructions + traceCache.put(traceStart, newTrace); + } + + return newTrace; + } + } + } + + private void compileTrace(Trace trace, int pc) { + if (DBT.VerifyAssertions) DBT._assert(trace.compiledTrace == null); + + trace.compiledTrace = new DBT_Trace(ps, pc); + trace.compiledTrace.compile(); + } + + private void executeTrace(Trace trace, int pc) { + + //check if the trace is being executed very frequently... + if (trace.value > 20) { + + if (DBT_Options.debugTranslation) + System.out.println("Switching to interpretation at address 0x" + Integer.toHexString(pc)); + + //yes, so we should rather try to execute a translated version + if (trace.compiledTrace == null) { + //compile the trace, if necessary + compileTrace(trace, pc); + if (DBT.VerifyAssertions) DBT._assert(trace.compiledTrace != null); + } + + //execute the trace + VM_CodeArray code = trace.compiledTrace.getCurrentCompiledMethod().getEntryCodeArray(); + ps.setCurrentInstructionAddress(DynamicCodeRunner.invokeCode(code, ps)); + } + else { + trace.value += trace.instructions.size(); + } + + Iterator<Interpreter.Instruction> instructions = trace.instructions.iterator(); + while (true) { + Interpreter.Instruction instr = instructions.next(); + instr.execute(); + + if (instructions.hasNext()) { + pc = instr.getSuccessor(pc); + ps.setCurrentInstructionAddress(pc); + } + else + break; + } + } + + public StagedEmulationController(ProcessSpace ps) { + super(ps); + interpreter = ps.createInterpreter(); + } + + @Override + public void run() { + int pc = ps.getCurrentInstructionAddress(); + + while (!ps.finished) { + + Trace trace = getTrace(pc); + executeTrace(trace, pc); + pc = ps.getCurrentInstructionAddress(); + } + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-07-29 13:13:15
|
Revision: 152 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=152&view=rev Author: michael_baer Date: 2007-07-29 06:13:16 -0700 (Sun, 29 Jul 2007) Log Message: ----------- - Made profiling during interpretation a functionality provided by the ExecutionController - Added new ExecutionController - Restructured branch profiling slightly Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java src/org/binarytranslator/generic/branchprofile/BranchProfile.java src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java src/org/binarytranslator/generic/decoder/CodeTranslator.java src/org/binarytranslator/generic/decoder/Interpreter.java src/org/binarytranslator/generic/execution/InterpreterController.java src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java src/org/binarytranslator/generic/os/process/ProcessSpace.java Added Paths: ----------- src/org/binarytranslator/generic/decoder/Disassembler.java src/org/binarytranslator/generic/execution/ProfilingPredecodingInterpreter.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-07-29 13:13:16 UTC (rev 152) @@ -9,7 +9,6 @@ import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; -import org.binarytranslator.generic.branchprofile.BranchProfile.BranchType; import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.decoder.Utils; @@ -23,7 +22,7 @@ * @author Michael Baer */ public class ARM_Interpreter implements Interpreter { - + /** The process space that we're interpreting.*/ protected final ARM_ProcessSpace ps; @@ -31,7 +30,7 @@ protected final ARM_Registers regs; /** The interpreter factory is creating the final instructions, which implement the Interpreter.Instruction interface. */ - protected final ARM_InstructionFactory<ARM_Instruction> instructionFactory; + protected final InterpreterFactory instructionFactory; public ARM_Interpreter(ARM_ProcessSpace ps) { this.ps = ps; @@ -41,9 +40,11 @@ /** Decodes the instruction at the given address.*/ public Instruction decode(int pc) { - + ARM_Instruction instruction; + instructionFactory.setInstructionAddress(pc); + if ((pc & 1) != 0) { short binaryInstruction = (short)ps.memory.loadInstruction16(pc & 0xFFFFFFFE); instruction = ARM_InstructionDecoder.Thumb.decode(binaryInstruction, instructionFactory); @@ -54,7 +55,7 @@ } if (instruction.getCondition() != Condition.AL) { - return new ConditionalDecorator(instruction); + return new ConditionalDecorator(instruction, pc); } return instruction; @@ -123,7 +124,7 @@ if (operand.getRegister() == ARM_Registers.PC) value = regs.readPC(); else - value =regs.get(operand.getRegister()); + value = regs.get(operand.getRegister()); value += operand.getOffset(); return; @@ -364,43 +365,66 @@ * instruction (or not). The instruction classes itself do not check any conditions. */ private final class ConditionalDecorator implements Interpreter.Instruction { + /** The conditional instruction. */ protected final ARM_Instruction conditionalInstruction; - private final Condition condition; + + /** The address of the successor of the conditional instruction. Can be -1, if it cannot be determined statically. */ + private final int conditionTrueSuccessor; + + /** The successor of this instruction, if the condition evaluates to false.*/ + private final int conditionFalseSuccessor; + + /** The address of the successor of this instrction if it is constant, otherwise -1. */ + private final int successorInstruction; + + /** The address of this instruction. */ + private final int instructionAddress; /** Decorates an ARM interpreter instruction, by making it execute conditionally. */ - protected ConditionalDecorator(ARM_Instruction i) { - conditionalInstruction = i; - this.condition = i.getCondition(); + protected ConditionalDecorator(ARM_Instruction i, int pc) { + this.conditionalInstruction = i; + + conditionTrueSuccessor = conditionalInstruction.getSuccessor(pc); + boolean inThumbMode = (pc & 1) == 0; + + if (conditionTrueSuccessor == pc + 4 && !inThumbMode) + successorInstruction = conditionTrueSuccessor; //ARM may have conditional instruction that are not jumps + else + successorInstruction = -1; + + conditionFalseSuccessor = pc + (inThumbMode ? 2 : 4); + instructionAddress = pc; } public void execute() { + if (isConditionTrue()) { - int nextInstruction = conditionalInstruction.getSuccessor(ps.getCurrentInstructionAddress()); conditionalInstruction.execute(); - if (nextInstruction != -1) - ps.setCurrentInstructionAddress(nextInstruction); + if (conditionTrueSuccessor != -1) { + ps.setCurrentInstructionAddress(conditionTrueSuccessor); + } + + if (successorInstruction != -1) { + ps.branchInfo.profileBranch(instructionAddress, conditionTrueSuccessor); + } } else { - ps.setCurrentInstructionAddress(ps.getCurrentInstructionAddress() + (regs.getThumbMode() ? 2 : 4)); + ps.setCurrentInstructionAddress(conditionFalseSuccessor); + + if (successorInstruction != -1) { + ps.branchInfo.profileBranch(instructionAddress, conditionFalseSuccessor); + } } } public int getSuccessor(int pc) { - //if this instruction is not a jump, then we can tell what the next instruction will be. - - int conditionalSuccessor = conditionalInstruction.getSuccessor(pc); - boolean thumbMode = (pc & 0x1) == 1; - - if (conditionalSuccessor == pc + 4 && !thumbMode) - return conditionalSuccessor; //ARM may have conditional non-jump instructions - else - return -1; + return successorInstruction; } /** Return true if the condition required by the conditional instruction is fulfilled, false otherwise.*/ private boolean isConditionTrue() { - switch (condition) { + switch (conditionalInstruction.getCondition()) { case AL: throw new RuntimeException("ARM32 instructions with a condition of AL (always) should not be decorated with a ConditionalDecorator."); @@ -450,7 +474,7 @@ return regs.isOverflowSet(); default: - throw new RuntimeException("Unexpected condition code: " + condition); + throw new RuntimeException("Unexpected condition code: " + conditionalInstruction.getCondition()); } } @@ -514,10 +538,6 @@ if (i.Rd == ARM_Registers.PC) { if (regs.getThumbMode()) result |= 1; - - if (DBT_Options.profileDuringInterpretation) { - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), result, BranchType.INDIRECT_BRANCH); - } } regs.set(i.Rd, result); @@ -533,13 +553,8 @@ setFlagsForSub(lhs, rhs); int result = lhs - rhs; - if (i.Rd == ARM_Registers.PC) { - if (regs.getThumbMode()) - result |= 1; - - if (DBT_Options.profileDuringInterpretation) { - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), result, BranchType.INDIRECT_BRANCH); - } + if (i.Rd == ARM_Registers.PC && regs.getThumbMode()) { + result |= 1; } regs.set(i.Rd, result); @@ -595,8 +610,13 @@ * out value. The value of the barrel shifter is stored within this variable. */ protected boolean shifterCarryOut; - protected DataProcessing_Logical(ARM_Instructions.DataProcessing instr) { + protected DataProcessing_Logical(ARM_Instructions.DataProcessing instr, int instructionAddress) { super(instr); + + if (DBT_Options.profileDuringInterpretation) { + if (i.getOpcode() == Opcode.MOV && i.operand2.getType() == OperandWrapper.Type.Register && i.operand2.getRegister() == ARM_Registers.LR) + ps.branchInfo.registerReturnSite(instructionAddress); + } } /** If the given OperandWrapper involves shifting a register, then this function will decoder the shift @@ -622,13 +642,6 @@ if (regs.getThumbMode()) result |= 1; - - if (DBT_Options.profileDuringInterpretation) { - if (i.getOpcode() == Opcode.MOV && i.operand2.getType() == OperandWrapper.Type.Register && i.operand2.getRegister() == ARM_Registers.LR) - ps.branchInfo.registerReturn(regs.get(ARM_Registers.PC), result); - else - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), result, BranchType.INDIRECT_BRANCH); - } } regs.set(i.Rd, result); @@ -651,8 +664,8 @@ /** Binary and. <code>Rd = op1 & op2 </code>.*/ private final class DataProcessing_And extends DataProcessing_Logical { - protected DataProcessing_And(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_And(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -665,8 +678,8 @@ /** Exclusive or. <code>Rd = op1 ^ op2 </code>.*/ private final class DataProcessing_Eor extends DataProcessing_Logical { - protected DataProcessing_Eor(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Eor(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -804,8 +817,8 @@ * <code>Flags = op1 & op2</code>*/ private final class DataProcessing_Tst extends DataProcessing_Logical { - protected DataProcessing_Tst(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Tst(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -818,8 +831,8 @@ * <code>Flags = op1 ^ op2</code> */ private final class DataProcessing_Teq extends DataProcessing_Logical { - protected DataProcessing_Teq(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Teq(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -859,8 +872,8 @@ /** Binary or. <code>Rd = op1 | op2</code>. */ private final class DataProcessing_Orr extends DataProcessing_Logical { - protected DataProcessing_Orr(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Orr(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -872,8 +885,8 @@ private final class DataProcessing_Mov extends DataProcessing_Logical { - protected DataProcessing_Mov(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Mov(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -888,8 +901,8 @@ * <code>Rd = op1 & (~op2)</code>.*/ private final class DataProcessing_Bic extends DataProcessing_Logical { - protected DataProcessing_Bic(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Bic(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -904,8 +917,8 @@ * <code>Rd = ~op2</code>.*/ private final class DataProcessing_Mvn extends DataProcessing_Logical { - protected DataProcessing_Mvn(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Mvn(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -1000,22 +1013,26 @@ /** Should writeback be performed? */ private final boolean doWriteback; - public BlockDataTransfer(ARM_Instructions.BlockDataTransfer instr) { + public BlockDataTransfer(ARM_Instructions.BlockDataTransfer instr, int instructionAddress) { i = instr; transferPC = i.transferRegister(ARM_Registers.PC); int regCount = 0; - for (int i = 0; i <= 14; i++) + for (int i = 0; i <= 14; i++) { if (this.i.transferRegister(i)) { registersToTransfer[regCount++] = i; } + } registersToTransfer[regCount] = -1; if (transferPC) regCount++; + if (DBT_Options.profileDuringInterpretation) + ps.branchInfo.registerReturnSite(instructionAddress); + if (!i.incrementBase) { if (i.postIndexing) { //post-indexing, backward reading @@ -1095,9 +1112,6 @@ nextAddress += 4; int newpc = ps.memory.load32(nextAddress); - if (DBT_Options.profileDuringInterpretation) - ps.branchInfo.registerReturn(regs.get(ARM_Registers.PC), newpc); - if (i.forceUser) { //when we are transferring the PC with a forced-user transfer, then we also want to //restore the CPSR from the SPSR. @@ -1177,30 +1191,18 @@ public void execute() { - int destination; - BranchType branchType; - - if (i.offset.getType() != OperandWrapper.Type.Immediate) { - branchType = BranchType.INDIRECT_BRANCH; - } - else { - branchType = BranchType.DIRECT_BRANCH; - } - + int destination; destination = regs.readPC() + ResolvedOperand.resolve(regs, i.offset); - if (DBT_Options.profileDuringInterpretation) { - if (i.link) { - ps.branchInfo.registerCall(regs.get(ARM_Registers.PC), destination, regs.get(ARM_Registers.PC) + i.size()); - } - else { - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), destination, branchType); - } - } - //if we're supposed to link, then write the previous address into the link register if (i.link) { - regs.set(ARM_Registers.LR, regs.get(ARM_Registers.PC) + i.size()); + int returnAddress = regs.get(ARM_Registers.PC) + i.size(); + + if (DBT_Options.profileDuringInterpretation) { + ps.branchInfo.registerCallSite(regs.get(ARM_Registers.PC), destination, returnAddress); + } + + regs.set(ARM_Registers.LR, returnAddress); } if (regs.getThumbMode()) @@ -1273,12 +1275,13 @@ //if we're supposed to link, then write the previous address into the link register if (i.link) { - regs.set(ARM_Registers.LR, regs.readPC() - (regs.getThumbMode() ? 2 : 4)); - ps.branchInfo.registerCall(regs.get(ARM_Registers.PC), targetAddress, regs.get(ARM_Registers.PC) + i.size()); + int returnAddress = regs.readPC() - i.size(); + regs.set(ARM_Registers.LR, returnAddress); + + if (DBT_Options.profileDuringInterpretation) { + ps.branchInfo.registerCallSite(regs.get(ARM_Registers.PC), targetAddress, returnAddress); + } } - else { - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), targetAddress, BranchType.DIRECT_BRANCH); - } //jump to the new address regs.set(ARM_Registers.PC, targetAddress); @@ -1372,8 +1375,8 @@ //get rid of the signs, if we're supposed to do unsigned multiplication if (i.unsigned) { - operand1 = operand1 & 0xFFFFFFFF; - operand2 = operand2 & 0xFFFFFFFF; + operand1 &= 0xFFFFFFFF; + operand2 &= 0xFFFFFFFF; } // calculate the result @@ -1634,11 +1637,6 @@ //finally, write the variable into a register regs.set(i.Rd, value); - - if (DBT_Options.profileDuringInterpretation) { - if (i.Rd == ARM_Registers.PC) - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), value, BranchType.INDIRECT_BRANCH); - } } else { //we are store a value from a register to memory. @@ -1743,6 +1741,8 @@ * the ARM_InstructionDecoder, which uses an abstract factory pattern to decode an instruction. */ private class InterpreterFactory implements ARM_InstructionFactory<ARM_Instruction> { + + private int instructionAddress; public ARM_Instruction createDataProcessing(int instr) { ARM_Instructions.DataProcessing i = new ARM_Instructions.DataProcessing(instr); @@ -1753,21 +1753,21 @@ case ADD: return new DataProcessing_Add(i); case AND: - return new DataProcessing_And(i); + return new DataProcessing_And(i, instructionAddress); case BIC: - return new DataProcessing_Bic(i); + return new DataProcessing_Bic(i, instructionAddress); case CMN: return new DataProcessing_Cmn(i); case CMP: return new DataProcessing_Cmp(i); case EOR: - return new DataProcessing_Eor(i); + return new DataProcessing_Eor(i, instructionAddress); case MOV: - return new DataProcessing_Mov(i); + return new DataProcessing_Mov(i, instructionAddress); case MVN: - return new DataProcessing_Mvn(i); + return new DataProcessing_Mvn(i, instructionAddress); case ORR: - return new DataProcessing_Orr(i); + return new DataProcessing_Orr(i, instructionAddress); case RSB: return new DataProcessing_Rsb(i); case RSC: @@ -1777,9 +1777,9 @@ case SUB: return new DataProcessing_Sub(i); case TEQ: - return new DataProcessing_Teq(i); + return new DataProcessing_Teq(i, instructionAddress); case TST: - return new DataProcessing_Tst(i); + return new DataProcessing_Tst(i, instructionAddress); case CLZ: return new DataProcessing_Clz(i); @@ -1788,8 +1788,12 @@ } } + public void setInstructionAddress(int pc) { + instructionAddress = pc; + } + public ARM_Instruction createBlockDataTransfer(int instr) { - return new BlockDataTransfer(new ARM_Instructions.BlockDataTransfer(instr)); + return new BlockDataTransfer(new ARM_Instructions.BlockDataTransfer(instr), instructionAddress); } public ARM_Instruction createBranch(int instr) { @@ -1854,7 +1858,7 @@ } public ARM_Instruction createBlockDataTransfer(short instr) { - return new BlockDataTransfer(new ARM_Instructions.BlockDataTransfer(instr)); + return new BlockDataTransfer(new ARM_Instructions.BlockDataTransfer(instr), instructionAddress); } public ARM_Instruction createBranch(short instr) { @@ -1874,21 +1878,21 @@ case ADD: return new DataProcessing_Add(i); case AND: - return new DataProcessing_And(i); + return new DataProcessing_And(i, instructionAddress); case BIC: - return new DataProcessing_Bic(i); + return new DataProcessing_Bic(i, instructionAddress); case CMN: return new DataProcessing_Cmn(i); case CMP: return new DataProcessing_Cmp(i); case EOR: - return new DataProcessing_Eor(i); + return new DataProcessing_Eor(i, instructionAddress); case MOV: - return new DataProcessing_Mov(i); + return new DataProcessing_Mov(i, instructionAddress); case MVN: - return new DataProcessing_Mvn(i); + return new DataProcessing_Mvn(i, instructionAddress); case ORR: - return new DataProcessing_Orr(i); + return new DataProcessing_Orr(i, instructionAddress); case RSB: return new DataProcessing_Rsb(i); case RSC: @@ -1898,9 +1902,9 @@ case SUB: return new DataProcessing_Sub(i); case TEQ: - return new DataProcessing_Teq(i); + return new DataProcessing_Teq(i, instructionAddress); case TST: - return new DataProcessing_Tst(i); + return new DataProcessing_Tst(i, instructionAddress); case CLZ: return new DataProcessing_Clz(i); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-07-29 13:13:16 UTC (rev 152) @@ -1,6 +1,5 @@ package org.binarytranslator.arch.arm.decoder; public class ARM_Options { - public final static boolean FLAG_LAZINESS = false; public final static boolean DATAPROCESSING_DECODER_FASTPATH = false; } Modified: src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java =================================================================== --- src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java 2007-07-29 13:13:16 UTC (rev 152) @@ -3942,7 +3942,7 @@ int target_address = ps.lr; if (LK != 0) { ps.lr = ps.getCurrentInstructionAddress() + 4; - ps.branchInfo.registerCall(ps.getCurrentInstructionAddress(), ps + ps.branchInfo.registerCallSite(ps.getCurrentInstructionAddress(), ps .getCurrentInstructionAddress() + 4, target_address); } // decode BO @@ -4593,7 +4593,7 @@ int target_address = ps.ctr; if (LK != 0) { ps.lr = ps.getCurrentInstructionAddress() + 4; - ps.branchInfo.registerCall(ps.getCurrentInstructionAddress(), ps + ps.branchInfo.registerCallSite(ps.getCurrentInstructionAddress(), ps .getCurrentInstructionAddress() + 4, target_address); } // decode BO @@ -11618,7 +11618,7 @@ } if (LK != 0) { ps.lr = ps.getCurrentInstructionAddress() + 4; - ps.branchInfo.registerCall(ps.getCurrentInstructionAddress(), ps + ps.branchInfo.registerCallSite(ps.getCurrentInstructionAddress(), ps .getCurrentInstructionAddress() + 4, target_address); } // decode BO @@ -11767,7 +11767,7 @@ } if (lk != 0) { ps.lr = ps.getCurrentInstructionAddress() + 4; - ps.branchInfo.registerCall(ps.getCurrentInstructionAddress(), ps + ps.branchInfo.registerCallSite(ps.getCurrentInstructionAddress(), ps .getCurrentInstructionAddress() + 4, target_address); } ps.setCurrentInstructionAddress(target_address); Modified: src/org/binarytranslator/generic/branchprofile/BranchProfile.java =================================================================== --- src/org/binarytranslator/generic/branchprofile/BranchProfile.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/branchprofile/BranchProfile.java 2007-07-29 13:13:16 UTC (rev 152) @@ -12,10 +12,12 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.util.HashSet; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; +import java.util.Map.Entry; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -49,10 +51,101 @@ private final SortedMap<Integer, ProcedureInformation> procedures; /** A set of switch like branchs sites and their destinations */ - private final SortedMap<Integer, Set<Integer>> branchSitesAndDestinations; + private final SortedMap<Integer, BranchInformation> branchSites; /** Global branch information */ private static BranchProfile global; + + /** + * Stores information on a single branch location. */ + private final static class BranchInformation { + + /** How often the branch instruction has been executed. */ + private int executionCount; + + /** The target addresses of the branch and how often they have been branched to. */ + private final Map<Integer, Integer> destinationsAndFrequencies; + + public BranchInformation() { + this.destinationsAndFrequencies = new HashMap<Integer, Integer>(); + } + + public BranchInformation(HashMap<Integer, Integer> destinationsAndFrequencies) { + this.destinationsAndFrequencies = destinationsAndFrequencies; + executionCount = 0; + + for (Entry<Integer, Integer> target : destinationsAndFrequencies.entrySet()) { + executionCount += target.getValue(); + } + } + + public void profile(int target) { + executionCount++; + Integer targetCount = destinationsAndFrequencies.get(target); + + targetCount = (targetCount == null) ? 1 : targetCount + 1; + destinationsAndFrequencies.put(target, targetCount); + } + + /** Returns a list of addresses that this branch jumps to. */ + public Set<Integer> getTargets() { + return destinationsAndFrequencies.keySet(); + } + + public Map<Integer, Integer> getTargetsAndFrequencies() { + return destinationsAndFrequencies; + } + + public void registerTargetSite(int target) { + if (destinationsAndFrequencies.get(target) == null) + destinationsAndFrequencies.put(target, 0); + } + + /** + * Loads a {@link BranchInformation} object from an XML element, given that the object + * was previously persisted by {@link #toXML(Document, Element)}. + * @param node + * The XML element that had been provided to {@link #toXML(Document, Element)}. + * @throws IOException + */ + public static BranchInformation fromXML(Element node) throws IOException { + HashMap<Integer, Integer> targetsAndFrequencies = new HashMap<Integer, Integer>(); + + for (int n = 0; n < node.getChildNodes().getLength(); n++) { + Node target = node.getChildNodes().item(n); + + if (target.getNodeType() != Node.ELEMENT_NODE) + continue; + + if (!target.getNodeName().equals("target")) + throw new IOException("File is not a valid XML branch profile."); + + int targetAddress = Integer.parseInt(((Element)target).getAttribute("address")); + int branchCount = Integer.parseInt(((Element)target).getAttribute("address")); + targetsAndFrequencies.put(targetAddress, branchCount); + } + + return new BranchInformation(targetsAndFrequencies); + } + + public void toXML(Document doc, Element parentNode) { + Element branchInfo = parentNode; + + Element targets = doc.createElement("targets"); + + for (Entry<Integer, Integer> branchTarget : destinationsAndFrequencies.entrySet()) { + int targetAddress = branchTarget.getKey(); + int branchCount = branchTarget.getValue(); + + Element branchTargetElement = doc.createElement("target"); + branchInfo.appendChild(branchTargetElement); + branchTargetElement.setAttribute("address", Integer.toString(targetAddress)); + branchTargetElement.setAttribute("branchCount", Integer.toString(branchCount)); + } + + branchInfo.appendChild(targets); + } + } /** * Constructor has 2 functions: (1) when making a local trace we don't want to @@ -62,10 +155,10 @@ public BranchProfile() { if (global == null) { global = this; - branchSitesAndDestinations = new TreeMap<Integer, Set<Integer>>(); + branchSites = new TreeMap<Integer, BranchInformation>(); } else { - branchSitesAndDestinations = global.branchSitesAndDestinations; + branchSites = global.branchSites; } procedures = new TreeMap<Integer, ProcedureInformation>(); } @@ -80,7 +173,7 @@ * @param ret * the address that will be returned to */ - public void registerCall(int pc, int dest, int ret) { + public void registerCallSite(int pc, int dest, int ret) { ProcedureInformation procedure = procedures.get(dest); if (procedure != null) { @@ -90,27 +183,66 @@ procedures.put(dest, procedure); } - registerBranch(pc, dest); + registerDynamicBranchSite(pc, dest); } + + /** + * Register a function return. + * + * @param pc + * the address of the return instruction + */ + public void registerReturnSite(int pc) { + + ProcedureInformation procedure = getLikelyProcedure(pc); + + if (procedure != null) { + procedure.registerReturn(pc); + } + } /** * Register a function return. * * @param pc - * the address of the branch instruction + * the address of the return instruction * @param lr * the return address (value of the link register) */ - public void registerReturn(int pc, int lr) { + public void registerReturnSite(int pc, int lr) { ProcedureInformation procedure = getLikelyProcedure(pc); if (procedure != null) { - procedure.registerReturn(pc, lr); + procedure.registerReturn(pc); } - registerBranch(pc, lr); + registerDynamicBranchSite(pc, lr); } + + /** + * Appends a branch from <code>origin</code> to <code>target</code> to the branch profile. + * + * @param origin + * The address that the branch is taking place from. + * @param target + * The branch target address. + */ + public void registerDynamicBranchSite(int origin, int target) { + //Perform the general branch registration, too + BranchInformation branch = branchSites.get(origin); + + if (branch != null) { + branch.registerTargetSite(target); + // This destination address is already registered + return; + } + else { + branch = new BranchInformation(); + branch.registerTargetSite(target); + branchSites.put(origin, branch); + } + } /** * Given an address within a procedure, returns the (most likely) procedure @@ -128,58 +260,19 @@ } } return null; - } - + } + /** - * Registers a branch from the address <code>origin</code> to the address <code>target</code>. - * The type of branch is determined by <code>type</code>, which is an ordinal from the - * {@link BranchType} enum. + * Records that a branch from <code>origin</code> to <code>target</code> has been observed while the program is running. * * @param origin - * The address from which the branch occurs. + * The address from which the branch took place. * @param target - * The address to which the program is branching. - * @param type - * The most likely type of the branch. This is taken from the {@link BranchType} enum. + * The address to which it took place. */ - public void registerBranch(int origin, int target, BranchType type) { - - switch (type) { - case CALL: - throw new RuntimeException("Use the more specific registerCall() for these cases."); - - case RETURN: - registerReturn(origin, target); - break; - - default: - registerBranch(origin, target); - } + public void profileBranch(int origin, int target) { + throw new RuntimeException("Not yet implemented."); } - - /** - * Appends a recorded branch from <code>origin</code> to <code>target</code> to the branch profile. - * - * @param origin - * The address that the branch is taking place from. - * @param target - * The branch target address. - */ - private void registerBranch(int origin, int target) { - //Perform the general branch registration, too - Set<Integer> dests = branchSitesAndDestinations.get(origin); - - if (dests != null && dests.contains(target)) { - // This destination address is already registered - return; - } - else { - dests = new HashSet<Integer>(); - branchSitesAndDestinations.put(origin, dests); - } - - dests.add(target); - } /** * Returns a list of known branch targets for the branch at address <code>pc</code>. @@ -191,7 +284,8 @@ * translated binary, if this list is not complete. */ public Set<Integer> getKnownBranchTargets(int pc) { - return branchSitesAndDestinations.get(pc); + BranchInformation branch = branchSites.get(pc); + return (branch == null) ? null : branch.getTargets(); } public void loadFromXML(String filename) throws IOException { @@ -234,17 +328,9 @@ if (!siteNode.getNodeName().equals("origin") || siteNode.getNodeType() != Node.ELEMENT_NODE) throw new IOException("File is not a valid XML branch profile."); - int pc = Integer.parseInt(((Element)siteNode).getAttribute("address")); - - for (int n = 0; n < siteNode.getChildNodes().getLength(); n++) { - Node target = siteNode.getChildNodes().item(n); - - if (!target.getNodeName().equals("target") || target.getNodeType() != Node.ELEMENT_NODE) - throw new IOException("File is not a valid XML branch profile."); - - int targetAddress = Integer.parseInt(((Element)target).getAttribute("address")); - registerBranch(pc, targetAddress); - } + int address = Integer.parseInt(((Element)siteNode).getAttribute("address")); + BranchInformation branchInfo = BranchInformation.fromXML((Element)siteNode); + branchSites.put(address, branchInfo); } } @@ -289,17 +375,16 @@ Element branchesElement = doc.createElement("branches"); root.appendChild(branchesElement); - - for (int pc : branchSitesAndDestinations.keySet()) { - Element branchSiteElement = doc.createElement("origin"); + + for (Entry<Integer, BranchInformation> branch : branchSites.entrySet()) { + + int address = branch.getKey(); + BranchInformation branchInfo = branch.getValue(); + + Element branchSiteElement = doc.createElement("branch"); branchesElement.appendChild(branchSiteElement); - branchSiteElement.setAttribute("address", Integer.toString(pc)); - - for (int target : getKnownBranchTargets(pc)) { - Element branchTargetElement = doc.createElement("target"); - branchSiteElement.appendChild(branchTargetElement); - branchTargetElement.setAttribute("address", Integer.toString(target)); - } + branchSiteElement.setAttribute("address", Integer.toString(address)); + branchInfo.toXML(doc, branchSiteElement); } //Output the resulting XML document Modified: src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java =================================================================== --- src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java 2007-07-29 13:13:16 UTC (rev 152) @@ -91,13 +91,12 @@ * * @param pc * the address of the branch instruction - * @param ret - * the address that will be returned to */ - public void registerReturn(int pc, int ret) { + public void registerReturn(int pc) { if (returnSites == null) { returnSites = new HashSet<Integer>(); } + returnSites.add(new Integer(pc)); } @@ -186,11 +185,7 @@ throw new Error("The given XML node is not a valid ProcedureInformation entity."); } } - - - - - + return pi; } } Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-07-29 13:13:16 UTC (rev 152) @@ -607,13 +607,15 @@ branch, (Laziness) targetLaziness.clone(), currentPC, targetPC, BranchType.CALL); unresolvedDirectBranches.add(unresolvedJump); - if (branchType == BranchType.CALL) - ps.branchInfo.registerCall(currentPC, targetPC, retAddr); - else - if (branchType == BranchType.RETURN) - ps.branchInfo.registerReturn(currentPC, targetPC); - else - ps.branchInfo.registerBranch(currentPC, targetPC, branchType); + switch (branchType) { + case CALL: + ps.branchInfo.registerCallSite(currentPC, targetPC, retAddr); + break; + + case RETURN: + ps.branchInfo.registerReturnSite(currentPC, targetPC); + break; + } } /** @@ -929,7 +931,7 @@ * the destination of the branch instruction */ public void registerBranchAndLink(int pc, int ret, int dest) { - ps.branchInfo.registerCall(pc, ret, dest); + ps.branchInfo.registerCallSite(pc, ret, dest); } /** Added: src/org/binarytranslator/generic/decoder/Disassembler.java =================================================================== --- src/org/binarytranslator/generic/decoder/Disassembler.java (rev 0) +++ src/org/binarytranslator/generic/decoder/Disassembler.java 2007-07-29 13:13:16 UTC (rev 152) @@ -0,0 +1,46 @@ +package org.binarytranslator.generic.decoder; + +public interface Disassembler { + /** + * Represents an instruction, after it has been decoded by a disassembler. + * The instruction should be printable in the format of the target system's assembly language. + * + * @author Michael Baer + */ + public interface Instruction { + /** + * Shall return the address of the instruction following this one in <i>code order</i>, given that + * the current instruction has been decoded from address <code>pc</code>. + * @param pc + * The address from which this instruction has been decoded. + * @return + * The address of the instruction following this one in code order. + */ + int getSuccessor(int pc); + + /** + * Shall return a string representation of the disassembled instruction. + * We might have used toString() here, but I wanted it to be obvious if a dedicated implementation + * of this method is missing. + * + * @return + * A string representation of the disassembled instruction. + * For example: + * <code> + * ADD r0, r1, #15 + * </code> + * for an ARM ADD instruction. + */ + String asString(); + } + + /** + * Disassemble the instruction at address <code>pc</code> and return an appropriate object representation. + * + * @param pc + * The address at which the instruction resides. + * @return + * An object representation of the said instruction. + */ + Instruction disassemble(int pc); +} Modified: src/org/binarytranslator/generic/decoder/Interpreter.java =================================================================== --- src/org/binarytranslator/generic/decoder/Interpreter.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/decoder/Interpreter.java 2007-07-29 13:13:16 UTC (rev 152) @@ -1,5 +1,9 @@ package org.binarytranslator.generic.decoder; +/** + * TODO: Add comments for this interface. + * + */ public interface Interpreter { public interface Instruction { Modified: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-07-29 13:13:16 UTC (rev 152) @@ -1,5 +1,6 @@ package org.binarytranslator.generic.execution; +import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.os.process.ProcessSpace; @@ -22,12 +23,19 @@ instruction.execute(); //System.out.println(ps.toString()); - pc = instruction.getSuccessor(pc); + int nextInstruction = instruction.getSuccessor(pc); - if (pc == -1) - pc = ps.getCurrentInstructionAddress(); - else - ps.setCurrentInstructionAddress(pc); + if (nextInstruction == -1) { + nextInstruction = ps.getCurrentInstructionAddress(); + + if (DBT_Options.profileDuringInterpretation) + ps.branchInfo.profileBranch(pc, ps.getCurrentInstructionAddress()); + } + else { + ps.setCurrentInstructionAddress(nextInstruction); + } + + pc = nextInstruction; } } } Modified: src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java =================================================================== --- src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java 2007-07-29 13:13:16 UTC (rev 152) @@ -8,7 +8,7 @@ import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.os.process.ProcessSpace; -public final class PredecodingThreadedInterpreter extends ExecutionController { +public class PredecodingThreadedInterpreter extends ExecutionController { private final HashMap<Integer, List<Interpreter.Instruction>> traceCache = new HashMap<Integer, List<Interpreter.Instruction>>(); private final Interpreter interpreter; @@ -42,16 +42,19 @@ return newTrace; } - private void executeTrace(List<Interpreter.Instruction> trace, int pc) { + protected void executeTrace(List<Interpreter.Instruction> trace, int pc) { Iterator<Interpreter.Instruction> instructions = trace.iterator(); - while (instructions.hasNext()) { + while (true) { Interpreter.Instruction instr = instructions.next(); instr.execute(); - pc = instr.getSuccessor(pc); - if (pc != -1) + if (instructions.hasNext()) { + pc = instr.getSuccessor(pc); ps.setCurrentInstructionAddress(pc); + } + else + break; } } @@ -61,7 +64,7 @@ } @Override - public void run() { + public final void run() { int pc = ps.getCurrentInstructionAddress(); while (!ps.finished) { Added: src/org/binarytranslator/generic/execution/ProfilingPredecodingInterpreter.java =================================================================== --- src/org/binarytranslator/generic/execution/ProfilingPredecodingInterpreter.java (rev 0) +++ src/org/binarytranslator/generic/execution/ProfilingPredecodingInterpreter.java 2007-07-29 13:13:16 UTC (rev 152) @@ -0,0 +1,40 @@ +package org.binarytranslator.generic.execution; + +import java.util.Iterator; +import java.util.List; +import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.decoder.Interpreter.Instruction; +import org.binarytranslator.generic.os.process.ProcessSpace; + +/** + * Adds runtime profiling capabilities to {@link PredecodingThreadedInterpreter}. + */ +public class ProfilingPredecodingInterpreter extends PredecodingThreadedInterpreter { + + public ProfilingPredecodingInterpreter(ProcessSpace ps) { + super(ps); + } + + @Override + protected void executeTrace(List<Instruction> trace, int pc) { + Iterator<Interpreter.Instruction> instructions = trace.iterator(); + while (true) { + Interpreter.Instruction instr = instructions.next(); + + if (instructions.hasNext()) { + instr.execute(); + pc = instr.getSuccessor(pc); + ps.setCurrentInstructionAddress(pc); + + } + else { + int instructionAdddress = ps.getCurrentInstructionAddress(); + instr.execute(); + pc = ps.getCurrentInstructionAddress(); + ps.branchInfo.profileBranch(instructionAdddress, pc); + break; + } + } + } + +} Modified: src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java 2007-07-29 13:13:16 UTC (rev 152) @@ -35,7 +35,7 @@ private int nextMemoryBlock = 1024*1024*1024; //start mapping libraries at 1GB (0x40000000) /** Maps a library name to a filename. */ - protected final HashMap<String, String> libNames = new HashMap<String, String>();; + protected final HashMap<String, String> libNames = new HashMap<String, String>(); public static class SharedObject { /** The libary's name. */ Modified: src/org/binarytranslator/generic/os/process/ProcessSpace.java =================================================================== --- src/org/binarytranslator/generic/os/process/ProcessSpace.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/os/process/ProcessSpace.java 2007-07-29 13:13:16 UTC (rev 152) @@ -155,15 +155,15 @@ switch (type) { case CALL: - branchInfo.registerCall(location, destination, returnAddress); + branchInfo.registerCallSite(location, destination, returnAddress); return; case RETURN: - branchInfo.registerReturn(location, destination); + branchInfo.registerReturnSite(location, destination); return; default: - branchInfo.registerBranch(location, destination, BranchType.values()[code]); + branchInfo.registerDynamicBranchSite(location, destination); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-07-11 16:34:30
|
Revision: 151 http://svn.sourceforge.net/pearcolator/?rev=151&view=rev Author: michael_baer Date: 2007-07-11 09:34:25 -0700 (Wed, 11 Jul 2007) Log Message: ----------- - Make sure that the runtime linker does not return a local symbol when we're trying to resolve a global symbol. Modified Paths: -------------- src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java Modified: src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java 2007-07-09 10:42:27 UTC (rev 150) +++ src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java 2007-07-11 16:34:25 UTC (rev 151) @@ -70,7 +70,7 @@ if (symbol.isUndefined()) { String symbolName = strTab.lookup(symbol.nameIdx); - value = resolveSymbolAddress(symbolName); + value = resolveSymbolAddress(symbolName, lib); if (value == -1) { //we allow only weak symbols to be unresolved Modified: src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java 2007-07-09 10:42:27 UTC (rev 150) +++ src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java 2007-07-11 16:34:25 UTC (rev 151) @@ -119,6 +119,7 @@ * This function is the main entry point into the dynamic linker and will steer the whole * linking process. */ + @Override public final void link() throws IOException { ELF_File.DynamicSection dynSection = file.getDynamicSection(); @@ -193,7 +194,7 @@ */ protected void callInitRoutines() throws IOException { //the linker has a special symbol that determines if we're currently starting up - int dl_starting_up = resolveSymbolAddress("_dl_starting_up"); + int dl_starting_up = resolveSymbolAddress("_dl_starting_up", null); if (dl_starting_up != -1) ps.memory.store32(dl_starting_up, 1); @@ -392,10 +393,13 @@ * * @param symbol * The name of the symbol that is to be resolved. + * @param obj + * The shared object for which we are trying to resolve the symbol address. Local symbols from + * this object will be returned as a match as well. * @return * The address of the symbol or -1, if the symbol's address could not be resolved. */ - protected final int resolveSymbolAddress(String symbol) throws IOException { + protected final int resolveSymbolAddress(String symbol, SharedObject obj) throws IOException { Iterator<SharedObject> libs = libraries.iterator(); //iterate over the symbol table of every library that we already loaded @@ -406,8 +410,10 @@ //see if <symbol> is defined within this library SymbolTable.Entry entry = hashTab.lookup(symbol); - if (entry != null && !entry.isUndefined()) - return entry.value + lib.loadedAt; + if (entry != null && !entry.isUndefined() && entry.binding != SymbolTable.STB_LOCAL) { + if (entry.binding == SymbolTable.STB_GLOBAL || lib == obj) + return entry.value + lib.loadedAt; + } } return -1; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-07-09 10:42:30
|
Revision: 150 http://svn.sourceforge.net/pearcolator/?rev=150&view=rev Author: michael_baer Date: 2007-07-09 03:42:27 -0700 (Mon, 09 Jul 2007) Log Message: ----------- - Added disassembler interface Modified Paths: -------------- src/org/binarytranslator/generic/os/process/ProcessSpace.java Modified: src/org/binarytranslator/generic/os/process/ProcessSpace.java =================================================================== --- src/org/binarytranslator/generic/os/process/ProcessSpace.java 2007-07-09 10:36:57 UTC (rev 149) +++ src/org/binarytranslator/generic/os/process/ProcessSpace.java 2007-07-09 10:42:27 UTC (rev 150) @@ -18,6 +18,7 @@ import org.binarytranslator.generic.branchprofile.BranchProfile.BranchType; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.decoder.CodeCache; +import org.binarytranslator.generic.decoder.Disassembler; import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.execution.GdbController.GdbTarget; import org.binarytranslator.generic.memory.Memory; @@ -80,9 +81,15 @@ throw new UnsupportedOperationException(); } + public Disassembler createDisassembler() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + /** Return a string disassembly of the instuction at the given address*/ @Uninterruptible - public abstract String disassembleInstruction(int pc) throws UnsupportedOperationException ; + public String disassembleInstruction(int pc) throws UnsupportedOperationException { + return createDisassembler().disassemble(pc).asString(); + } /** * Given an ELF binary loader, create the appropriate process space This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |