Mercurial > hg > truffle
view graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiTargetMethod.java @ 4292:48cbd78fa964
First draft of SSA-based linear scan allocator
author | Christian Wimmer <Christian.Wimmer@Oracle.com> |
---|---|
date | Tue, 17 Jan 2012 19:38:48 -0800 |
parents | aaac4894175c |
children | 07bcee8b70a4 |
line wrap: on
line source
/* * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.max.cri.ci; import java.io.*; import java.util.*; import com.oracle.max.cri.ri.*; /** * Represents the output from compiling a method, including the compiled machine code, associated data and references, * relocation information, deoptimization information, etc. It is the essential component of a {@link CiResult}, which also includes * {@linkplain CiStatistics compilation statistics} and {@linkplain CiBailout failure information}. */ public class CiTargetMethod implements Serializable { /** * */ private static final long serialVersionUID = -1319947729753702434L; /** * Represents a code position with associated additional information. */ public abstract static class Site implements Serializable { /** * */ private static final long serialVersionUID = -8214214947651979102L; /** * The position (or offset) of this site with respect to the start of the target method. */ public final int pcOffset; public Site(int pos) { this.pcOffset = pos; } } /** * Represents a safepoint with associated debug info. */ public static class Safepoint extends Site implements Comparable<Safepoint> { /** * */ private static final long serialVersionUID = 2479806696381720162L; public final CiDebugInfo debugInfo; Safepoint(int pcOffset, CiDebugInfo debugInfo) { super(pcOffset); this.debugInfo = debugInfo; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(pcOffset); sb.append("[<safepoint>]"); appendDebugInfo(sb, debugInfo); return sb.toString(); } @Override public int compareTo(Safepoint o) { if (pcOffset < o.pcOffset) { return -1; } else if (pcOffset > o.pcOffset) { return 1; } return 0; } } /** * Represents a call in the code. */ public static final class Call extends Safepoint { /** * */ private static final long serialVersionUID = 1440741241631046954L; /** * The target of the call. */ public final Object target; /** * The size of the call instruction. */ public final int size; /** * Specifies if this call is direct or indirect. A direct call has an immediate operand encoding * the absolute or relative (to the call itself) address of the target. An indirect call has a * register or memory operand specifying the target address of the call. */ public final boolean direct; Call(Object target, int pcOffset, int size, boolean direct, CiDebugInfo debugInfo) { super(pcOffset, debugInfo); this.size = size; this.target = target; this.direct = direct; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(pcOffset); sb.append('['); sb.append(target); sb.append(']'); if (debugInfo != null) { appendDebugInfo(sb, debugInfo); } return sb.toString(); } } /** * Represents a reference to data from the code. The associated data can be any constant. */ public static final class DataPatch extends Site { /** * */ private static final long serialVersionUID = 5771730331604867476L; public final CiConstant constant; public final int alignment; DataPatch(int pcOffset, CiConstant data, int alignment) { super(pcOffset); this.constant = data; this.alignment = alignment; } @Override public String toString() { return String.format("%d[<data patch referring to data %s>]", pcOffset, constant); } } /** * Provides extra information about instructions or data at specific positions in {@link CiTargetMethod#targetCode()}. * This is optional information that can be used to enhance a disassembly of the code. */ public abstract static class CodeAnnotation implements Serializable { /** * */ private static final long serialVersionUID = -7903959680749520748L; public final int position; public CodeAnnotation(int position) { this.position = position; } } /** * A string comment about one or more instructions at a specific position in the code. */ public static final class CodeComment extends CodeAnnotation { /** * */ private static final long serialVersionUID = 6802287188701961401L; public final String value; public CodeComment(int position, String comment) { super(position); this.value = comment; } @Override public String toString() { return getClass().getSimpleName() + "@" + position + ": " + value; } } /** * Labels some inline data in the code. */ public static final class InlineData extends CodeAnnotation { /** * */ private static final long serialVersionUID = 305997507263827108L; public final int size; public InlineData(int position, int size) { super(position); this.size = size; } @Override public String toString() { return getClass().getSimpleName() + "@" + position + ": size=" + size; } } /** * Describes a table of signed offsets embedded in the code. The offsets are relative to the starting * address of the table. This type of table maybe generated when translating a multi-way branch * based on a key value from a dense value set (e.g. the {@code tableswitch} JVM instruction). * * The table is indexed by the contiguous range of integers from {@link #low} to {@link #high} inclusive. */ public static final class JumpTable extends CodeAnnotation { /** * */ private static final long serialVersionUID = 2222194398353801831L; /** * The low value in the key range (inclusive). */ public final int low; /** * The high value in the key range (inclusive). */ public final int high; /** * The size (in bytes) of each table entry. */ public final int entrySize; public JumpTable(int position, int low, int high, int entrySize) { super(position); this.low = low; this.high = high; this.entrySize = entrySize; } @Override public String toString() { return getClass().getSimpleName() + "@" + position + ": [" + low + " .. " + high + "]"; } } /** * Describes a table of key and offset pairs. The offset in each table entry is relative to the address of * the table. This type of table maybe generated when translating a multi-way branch * based on a key value from a sparse value set (e.g. the {@code lookupswitch} JVM instruction). */ public static final class LookupTable extends CodeAnnotation { /** * */ private static final long serialVersionUID = 8367952567559116160L; /** * The number of entries in the table. */ public final int npairs; /** * The size (in bytes) of entry's key. */ public final int keySize; /** * The size (in bytes) of entry's offset value. */ public final int offsetSize; public LookupTable(int position, int npairs, int keySize, int offsetSize) { super(position); this.npairs = npairs; this.keySize = keySize; this.offsetSize = offsetSize; } @Override public String toString() { return getClass().getSimpleName() + "@" + position + ": [npairs=" + npairs + ", keySize=" + keySize + ", offsetSize=" + offsetSize + "]"; } } /** * Represents exception handler information for a specific code position. It includes the catch code position as * well as the caught exception type. */ public static final class ExceptionHandler extends Site { /** * */ private static final long serialVersionUID = 4897339464722665281L; public final int bci; public final int scopeLevel; public final int handlerPos; public final int handlerBci; public final RiType exceptionType; ExceptionHandler(int pcOffset, int bci, int scopeLevel, int handlerPos, int handlerBci, RiType exceptionType) { super(pcOffset); this.bci = bci; this.scopeLevel = scopeLevel; this.handlerPos = handlerPos; this.handlerBci = handlerBci; this.exceptionType = exceptionType; } @Override public String toString() { return String.format("%d[<exception edge to %d with type %s>]", pcOffset, handlerPos, (exceptionType == null) ? "null" : exceptionType); } } public static final class Mark extends Site { /** * */ private static final long serialVersionUID = 3612943150662354844L; public final Object id; public final Mark[] references; Mark(int pcOffset, Object id, Mark[] references) { super(pcOffset); this.id = id; this.references = references; } @Override public String toString() { if (id == null) { return String.format("%d[<mark with %d references>]", pcOffset, references.length); } else if (id instanceof Integer) { return String.format("%d[<mark with %d references and id %s>]", pcOffset, references.length, Integer.toHexString((Integer) id)); } else { return String.format("%d[<mark with %d references and id %s>]", pcOffset, references.length, id.toString()); } } } /** * List of safepoints, sorted by {@link Site#pcOffset}. */ public final List<Safepoint> safepoints = new ArrayList<>(); /** * List of data references. */ public final List<DataPatch> dataReferences = new ArrayList<>(); /** * List of exception handlers. */ public final List<ExceptionHandler> exceptionHandlers = new ArrayList<>(); /** * List of marks. */ public final List<Mark> marks = new ArrayList<>(); private int frameSize = -1; private int customStackAreaOffset = -1; private int registerRestoreEpilogueOffset = -1; /** * The buffer containing the emitted machine code. */ private byte[] targetCode; /** * The leading number of bytes in {@link #targetCode} containing the emitted machine code. */ private int targetCodeSize; private ArrayList<CodeAnnotation> annotations; private CiAssumptions assumptions; /** * Constructs a new target method. */ public CiTargetMethod() { } public void setAssumptions(CiAssumptions assumptions) { this.assumptions = assumptions; } public CiAssumptions assumptions() { return assumptions; } /** * Sets the frame size in bytes. Does not include the return address pushed onto the * stack, if any. * * @param size the size of the frame in bytes */ public void setFrameSize(int size) { frameSize = size; } /** * Sets the machine that has been generated by the compiler. * * @param code the machine code generated * @param size the size of the machine code */ public void setTargetCode(byte[] code, int size) { targetCode = code; targetCodeSize = size; } /** * Records a reference to the data section in the code section (e.g. to load an integer or floating point constant). * * @param codePos the position in the code where the data reference occurs * @param data the data that is referenced * @param alignment the alignment requirement of the data or 0 if there is no alignment requirement */ public void recordDataReference(int codePos, CiConstant data, int alignment) { assert codePos >= 0 && data != null; dataReferences.add(new DataPatch(codePos, data, alignment)); } /** * Records a call in the code array. * * @param codePos the position of the call in the code array * @param size the size of the call instruction * @param target the {@link RiRuntime#asCallTarget(Object) target} being called * @param debugInfo the debug info for the call * @param direct specifies if this is a {@linkplain Call#direct direct} call */ public void recordCall(int codePos, int size, Object target, CiDebugInfo debugInfo, boolean direct) { final Call call = new Call(target, codePos, size, direct, debugInfo); addSafepoint(call); } /** * Records an exception handler for this method. * * @param codePos the position in the code that is covered by the handler * @param handlerPos the position of the handler * @param throwableType the type of exceptions handled by the handler */ public void recordExceptionHandler(int codePos, int bci, int scopeLevel, int handlerPos, int handlerBci, RiType throwableType) { exceptionHandlers.add(new ExceptionHandler(codePos, bci, scopeLevel, handlerPos, handlerBci, throwableType)); } /** * Records a safepoint in the code array. * * @param codePos the position of the safepoint in the code array * @param debugInfo the debug info for the safepoint */ public void recordSafepoint(int codePos, CiDebugInfo debugInfo) { addSafepoint(new Safepoint(codePos, debugInfo)); } private void addSafepoint(Safepoint safepoint) { // The safepoints list must always be sorted if (!safepoints.isEmpty() && safepoints.get(safepoints.size() - 1).pcOffset >= safepoint.pcOffset) { // This re-sorting should be very rare Collections.sort(safepoints); } safepoints.add(safepoint); } /** * Records an instruction mark within this method. * * @param codePos the position in the code that is covered by the handler * @param id the identifier for this mark * @param references an array of other marks that this mark references */ public Mark recordMark(int codePos, Object id, Mark[] references) { Mark mark = new Mark(codePos, id, references); marks.add(mark); return mark; } /** * Allows a method to specify the offset of the epilogue that restores the callee saved registers. Must be called * iff the method is a callee saved method and stores callee registers on the stack. * * @param registerRestoreEpilogueOffset the offset in the machine code where the epilogue begins */ public void setRegisterRestoreEpilogueOffset(int registerRestoreEpilogueOffset) { assert this.registerRestoreEpilogueOffset == -1; this.registerRestoreEpilogueOffset = registerRestoreEpilogueOffset; } /** * The frame size of the method in bytes. * * @return the frame size */ public int frameSize() { assert frameSize != -1 : "frame size not yet initialized!"; return frameSize; } /** * @return the code offset of the start of the epilogue that restores all callee saved registers, or -1 if this is * not a callee saved method */ public int registerRestoreEpilogueOffset() { return registerRestoreEpilogueOffset; } /** * Offset in bytes for the custom stack area (relative to sp). * @return the offset in bytes */ public int customStackAreaOffset() { return customStackAreaOffset; } /** * @see #customStackAreaOffset() * @param offset */ public void setCustomStackAreaOffset(int offset) { customStackAreaOffset = offset; } /** * @return the machine code generated for this method */ public byte[] targetCode() { return targetCode; } /** * @return the size of the machine code generated for this method */ public int targetCodeSize() { return targetCodeSize; } /** * @return the code annotations or {@code null} if there are none */ public List<CodeAnnotation> annotations() { return annotations; } public void addAnnotation(CodeAnnotation annotation) { assert annotation != null; if (annotations == null) { annotations = new ArrayList<>(); } annotations.add(annotation); } private static void appendDebugInfo(StringBuilder sb, CiDebugInfo info) { if (info != null) { appendRefMap(sb, "stackMap", info.frameRefMap); appendRefMap(sb, "registerMap", info.registerRefMap); CiCodePos codePos = info.codePos; if (codePos != null) { CiUtil.appendLocation(sb.append(" "), codePos.method, codePos.bci); if (info.hasFrame()) { sb.append(" #locals=").append(info.frame().numLocals).append(" #expr=").append(info.frame().numStack); if (info.frame().numLocks > 0) { sb.append(" #locks=").append(info.frame().numLocks); } } } } } private static void appendRefMap(StringBuilder sb, String name, CiBitMap map) { if (map != null) { sb.append(' ').append(name).append('[').append(map.toBinaryString()).append(']'); } } }