/*
* Copyright (c) 2007, 2012, 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.sun.max.ins.method;
import java.util.*;
import com.sun.cri.bytecode.*;
import com.sun.max.ins.*;
import com.sun.max.ins.debug.*;
import com.sun.max.tele.*;
import com.sun.max.tele.object.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.classfile.constant.*;
/**
* Base class for views of disassembled machine code for a single method in the VM.
*/
public abstract class MachineCodeViewer extends CodeViewer {
private final MaxMachineCodeRoutine machineCode;
private TeleConstantPool teleConstantPool;
private ConstantPool localConstantPool;
private String[] rowToTagText;
protected MachineCodeViewer(Inspection inspection, MethodView parent, MaxMachineCodeRoutine machineCode) {
super(inspection, parent);
this.machineCode = machineCode;
updateMachineCodeInfo();
}
/**
* Updates all information derived from the machine code.
*/
private void updateMachineCodeInfo() {
final MaxMachineCodeInfo machineCodeInfo = this.machineCode.getMachineCodeInfo();
final int machineInstructionCount = machineCodeInfo.length();
this.rowToTagText = new String[machineInstructionCount];
rowToStackFrame = new MaxStackFrame[machineInstructionCount];
teleConstantPool = null;
localConstantPool = null;
Arrays.fill(rowToTagText, "");
if (this.machineCode instanceof MaxCompilation) {
final MaxCompilation compilation = (MaxCompilation) this.machineCode;
final TeleClassMethodActor teleClassMethodActor = compilation.getTeleClassMethodActor();
if (teleClassMethodActor != null) {
final TeleCodeAttribute teleCodeAttribute = teleClassMethodActor.getTeleCodeAttribute();
if (teleCodeAttribute != null) {
teleConstantPool = teleCodeAttribute.getTeleConstantPool();
ClassMethodActor classMethodActor = teleClassMethodActor.classMethodActor();
localConstantPool = classMethodActor == null ? null : classMethodActor.codeAttribute().cp;
for (int index = 0; index < machineCodeInfo.length(); index++) {
final int opcode = machineCodeInfo.opcode(index);
if (machineCodeInfo.isBytecodeBoundary(index) && opcode >= 0) {
if (opcode == Integer.MAX_VALUE) {
rowToTagText[index] = "<epilogue>";
} else {
rowToTagText[index] = machineCodeInfo.debugInfoAt(index).codePos.bci + ": " + Bytecodes.nameOf(opcode);
}
} else {
rowToTagText[index] = "";
}
}
} else {
// Must be a hand crafted stub
}
}
}
updateStackCache();
}
@Override
public MethodCodeKind codeKind() {
return MethodCodeKind.MACHINE_CODE;
}
@Override
public String codeViewerKindName() {
return "Machine Code";
}
/**
* Rebuilds the cache of stack information if needed, based on the thread that is the current focus.
* <br>
* Identifies for each row (instruction) a stack frame (if any) that is related to the instruction.
* In the case of the top frame, this would be the row (instruction) at the current IP.
* In the case of other frames, this would be the row (instruction) that is the call return site.
*
*/
@Override
protected void updateStackCache() {
final MaxThread thread = focus().thread();
if (thread == null) {
return;
}
final List<MaxStackFrame> frames = thread.stack().frames(StackView.DEFAULT_MAX_FRAMES_DISPLAY);
Arrays.fill(rowToStackFrame, null);
// For very deep stacks (e.g. when debugging stack overflow handling),
// it's faster to loop over the frames and then only loop over the instructions for each
// frame related to the machine code represented by this viewer.
final MaxMemoryRegion machineCodeRegion = machineCode().memoryRegion();
for (MaxStackFrame frame : frames) {
final MaxCodeLocation frameCodeLocation = frame.codeLocation();
final MaxMachineCodeRoutine machineCode = frame.machineCode();
if (frameCodeLocation != null && machineCode != null) {
final boolean isFrameForThisCode =
frame instanceof MaxStackFrame.Compiled ?
machineCodeRegion.overlaps(machineCode.memoryRegion()) :
machineCodeRegion.contains(frameCodeLocation.address());
if (isFrameForThisCode) {
final MaxMachineCodeInfo machineCodeInfo = machineCode.getMachineCodeInfo();
for (int row = 0; row < machineCodeInfo.length(); row++) {
if (machineCodeInfo.instruction(row).address.equals(frameCodeLocation.address())) {
rowToStackFrame[row] = frame;
break;
}
}
}
}
}
}
/**
* @return surrogate for the machine in the VM for the method being viewed.
*/
protected MaxMachineCodeRoutine machineCode() {
return machineCode;
}
/**
* @return surrogate for the {@link ConstantPool} in the VM for the method being viewed.
*/
protected final TeleConstantPool teleConstantPool() {
return teleConstantPool;
}
/**
* @return local {@link ConstantPool} for the class containing the method in the VM being viewed.
*/
protected final ConstantPool localConstantPool() {
return localConstantPool;
}
/**
* Does the instruction address have a machine code breakpoint set in the VM.
*/
protected MaxBreakpoint getMachineCodeBreakpointAtRow(int row) {
return vm().breakpointManager().findBreakpoint(machineCode.getMachineCodeInfo().instructionLocation(row));
}
protected final String rowToTagText(int row) {
return rowToTagText[row];
}
}