/*
 * Copyright (c) 2002, 2008, 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 sun.jvm.hotspot.debugger.windbg;

import sun.jvm.hotspot.debugger.*;

class WindbgAddress implements Address {
  protected WindbgDebugger debugger;
  protected long addr;

  WindbgAddress(WindbgDebugger debugger, long addr) {
    this.debugger = debugger;
    this.addr = addr;
  }

  //
  // Basic Java routines
  //

  public boolean equals(Object arg) {
    if (arg == null) {
      return false;
    }

    if (!(arg instanceof WindbgAddress)) {
      return false;
    }

    return (addr == ((WindbgAddress) arg).addr);
  }

  public int hashCode() {
    // FIXME: suggestions on a better hash code?
    return (int) addr;
  }

  public String toString() {
    return debugger.addressValueToString(addr);
  }

  //
  // C/C++-related routines
  //

  public long getCIntegerAt(long offset, long numBytes, boolean isUnsigned) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readCInteger(addr + offset, numBytes, isUnsigned);
  }

  public Address getAddressAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readAddress(addr + offset);
  }

  public Address getCompOopAddressAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readCompOopAddress(addr + offset);
  }

  public Address getCompKlassAddressAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readCompKlassAddress(addr + offset);
  }

  //
  // Java-related routines
  //

  public boolean getJBooleanAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readJBoolean(addr + offset);
  }

  public byte getJByteAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readJByte(addr + offset);
  }

  public char getJCharAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readJChar(addr + offset);
  }

  public double getJDoubleAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readJDouble(addr + offset);
  }

  public float getJFloatAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readJFloat(addr + offset);
  }

  public int getJIntAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readJInt(addr + offset);
  }

  public long getJLongAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readJLong(addr + offset);
  }

  public short getJShortAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
    return debugger.readJShort(addr + offset);
  }

  public OopHandle getOopHandleAt(long offset)
    throws UnalignedAddressException, UnmappedAddressException, NotInHeapException {
    return debugger.readOopHandle(addr + offset);
  }

  public OopHandle getCompOopHandleAt(long offset)
    throws UnalignedAddressException, UnmappedAddressException, NotInHeapException {
    return debugger.readCompOopHandle(addr + offset);
  }
  //
  // C/C++-related mutators
  //

  public void setCIntegerAt(long offset, long numBytes, long value) {
    throw new DebuggerException("Unimplemented");
  }
  public void setAddressAt(long offset, Address value) {
    throw new DebuggerException("Unimplemented");
  }

  //
  // Java-related mutators
  //

  // Mutators -- not implemented for now (FIXME)
  public void       setJBooleanAt      (long offset, boolean value)
    throws UnmappedAddressException, UnalignedAddressException {
    throw new DebuggerException("Unimplemented");
  }
  public void       setJByteAt         (long offset, byte value)
    throws UnmappedAddressException, UnalignedAddressException {
    throw new DebuggerException("Unimplemented");
  }
  public void       setJCharAt         (long offset, char value)
    throws UnmappedAddressException, UnalignedAddressException {
    throw new DebuggerException("Unimplemented");
  }
  public void       setJDoubleAt       (long offset, double value)
    throws UnmappedAddressException, UnalignedAddressException {
    throw new DebuggerException("Unimplemented");
  }
  public void       setJFloatAt        (long offset, float value)
    throws UnmappedAddressException, UnalignedAddressException {
    throw new DebuggerException("Unimplemented");
  }
  public void       setJIntAt          (long offset, int value)
    throws UnmappedAddressException, UnalignedAddressException {
    throw new DebuggerException("Unimplemented");
  }
  public void       setJLongAt         (long offset, long value)
    throws UnmappedAddressException, UnalignedAddressException {
    throw new DebuggerException("Unimplemented");
  }
  public void       setJShortAt        (long offset, short value)
    throws UnmappedAddressException, UnalignedAddressException {
    throw new DebuggerException("Unimplemented");
  }
  public void       setOopHandleAt     (long offset, OopHandle value)
    throws UnmappedAddressException, UnalignedAddressException {
    throw new DebuggerException("Unimplemented");
  }

  //
  // Arithmetic operations -- necessary evil.
  //

  public Address    addOffsetTo       (long offset) throws UnsupportedOperationException {
    long value = addr + offset;
    if (value == 0) {
      return null;
    }
    return new WindbgAddress(debugger, value);
  }

  public OopHandle  addOffsetToAsOopHandle(long offset) throws UnsupportedOperationException {
    long value = addr + offset;
    if (value == 0) {
      return null;
    }
    return new WindbgOopHandle(debugger, value);
  }

  
(FIXME: any signed/unsigned issues? Should this work for OopHandles?)
/** (FIXME: any signed/unsigned issues? Should this work for OopHandles?) */
public long minus(Address arg) { if (arg == null) { return addr; } return addr - ((WindbgAddress) arg).addr; } // Two's complement representation. // All negative numbers are larger than positive numbers. // Numbers with the same sign can be compared normally. // Test harness is below in main(). public boolean lessThan (Address a) { if (a == null) { return false; } WindbgAddress arg = (WindbgAddress) a; if ((addr >= 0) && (arg.addr < 0)) { return true; } if ((addr < 0) && (arg.addr >= 0)) { return false; } return (addr < arg.addr); } public boolean lessThanOrEqual (Address a) { if (a == null) { return false; } WindbgAddress arg = (WindbgAddress) a; if ((addr >= 0) && (arg.addr < 0)) { return true; } if ((addr < 0) && (arg.addr >= 0)) { return false; } return (addr <= arg.addr); } public boolean greaterThan (Address a) { if (a == null) { return true; } WindbgAddress arg = (WindbgAddress) a; if ((addr >= 0) && (arg.addr < 0)) { return false; } if ((addr < 0) && (arg.addr >= 0)) { return true; } return (addr > arg.addr); } public boolean greaterThanOrEqual(Address a) { if (a == null) { return true; } WindbgAddress arg = (WindbgAddress) a; if ((addr >= 0) && (arg.addr < 0)) { return false; } if ((addr < 0) && (arg.addr >= 0)) { return true; } return (addr >= arg.addr); } public Address andWithMask(long mask) throws UnsupportedOperationException { long value = addr & mask; if (value == 0) { return null; } return new WindbgAddress(debugger, value); } public Address orWithMask(long mask) throws UnsupportedOperationException { long value = addr | mask; if (value == 0) { return null; } return new WindbgAddress(debugger, value); } public Address xorWithMask(long mask) throws UnsupportedOperationException { long value = addr ^ mask; if (value == 0) { return null; } return new WindbgAddress(debugger, value); } public long asLongValue() { return addr; } //-------------------------------------------------------------------------------- // Internals only below this point // long getValue() { return addr; } private static void check(boolean arg, String failMessage) { if (!arg) { System.err.println(failMessage + ": FAILED"); System.exit(1); } } // Test harness public static void main(String[] args) { // p/n indicates whether the interior address is really positive // or negative. In unsigned terms, p1 < p2 < n1 < n2. WindbgAddress p1 = new WindbgAddress(null, 0x7FFFFFFFFFFFFFF0L); WindbgAddress p2 = (WindbgAddress) p1.addOffsetTo(10); WindbgAddress n1 = (WindbgAddress) p2.addOffsetTo(10); WindbgAddress n2 = (WindbgAddress) n1.addOffsetTo(10); // lessThan positive tests check(p1.lessThan(p2), "lessThan 1"); check(p1.lessThan(n1), "lessThan 2"); check(p1.lessThan(n2), "lessThan 3"); check(p2.lessThan(n1), "lessThan 4"); check(p2.lessThan(n2), "lessThan 5"); check(n1.lessThan(n2), "lessThan 6"); // lessThan negative tests check(!p1.lessThan(p1), "lessThan 7"); check(!p2.lessThan(p2), "lessThan 8"); check(!n1.lessThan(n1), "lessThan 9"); check(!n2.lessThan(n2), "lessThan 10"); check(!p2.lessThan(p1), "lessThan 11"); check(!n1.lessThan(p1), "lessThan 12"); check(!n2.lessThan(p1), "lessThan 13"); check(!n1.lessThan(p2), "lessThan 14"); check(!n2.lessThan(p2), "lessThan 15"); check(!n2.lessThan(n1), "lessThan 16"); // lessThanOrEqual positive tests check(p1.lessThanOrEqual(p1), "lessThanOrEqual 1"); check(p2.lessThanOrEqual(p2), "lessThanOrEqual 2"); check(n1.lessThanOrEqual(n1), "lessThanOrEqual 3"); check(n2.lessThanOrEqual(n2), "lessThanOrEqual 4"); check(p1.lessThanOrEqual(p2), "lessThanOrEqual 5"); check(p1.lessThanOrEqual(n1), "lessThanOrEqual 6"); check(p1.lessThanOrEqual(n2), "lessThanOrEqual 7"); check(p2.lessThanOrEqual(n1), "lessThanOrEqual 8"); check(p2.lessThanOrEqual(n2), "lessThanOrEqual 9"); check(n1.lessThanOrEqual(n2), "lessThanOrEqual 10"); // lessThanOrEqual negative tests check(!p2.lessThanOrEqual(p1), "lessThanOrEqual 11"); check(!n1.lessThanOrEqual(p1), "lessThanOrEqual 12"); check(!n2.lessThanOrEqual(p1), "lessThanOrEqual 13"); check(!n1.lessThanOrEqual(p2), "lessThanOrEqual 14"); check(!n2.lessThanOrEqual(p2), "lessThanOrEqual 15"); check(!n2.lessThanOrEqual(n1), "lessThanOrEqual 16"); // greaterThan positive tests check(n2.greaterThan(p1), "greaterThan 1"); check(n2.greaterThan(p2), "greaterThan 2"); check(n2.greaterThan(n1), "greaterThan 3"); check(n1.greaterThan(p1), "greaterThan 4"); check(n1.greaterThan(p2), "greaterThan 5"); check(p2.greaterThan(p1), "greaterThan 6"); // greaterThan negative tests check(!p1.greaterThan(p1), "greaterThan 7"); check(!p2.greaterThan(p2), "greaterThan 8"); check(!n1.greaterThan(n1), "greaterThan 9"); check(!n2.greaterThan(n2), "greaterThan 10"); check(!p1.greaterThan(n2), "greaterThan 11"); check(!p2.greaterThan(n2), "greaterThan 12"); check(!n1.greaterThan(n2), "greaterThan 13"); check(!p1.greaterThan(n1), "greaterThan 14"); check(!p2.greaterThan(n1), "greaterThan 15"); check(!p1.greaterThan(p2), "greaterThan 16"); // greaterThanOrEqual positive tests check(p1.greaterThanOrEqual(p1), "greaterThanOrEqual 1"); check(p2.greaterThanOrEqual(p2), "greaterThanOrEqual 2"); check(n1.greaterThanOrEqual(n1), "greaterThanOrEqual 3"); check(n2.greaterThanOrEqual(n2), "greaterThanOrEqual 4"); check(n2.greaterThanOrEqual(p1), "greaterThanOrEqual 5"); check(n2.greaterThanOrEqual(p2), "greaterThanOrEqual 6"); check(n2.greaterThanOrEqual(n1), "greaterThanOrEqual 7"); check(n1.greaterThanOrEqual(p1), "greaterThanOrEqual 8"); check(n1.greaterThanOrEqual(p2), "greaterThanOrEqual 9"); check(p2.greaterThanOrEqual(p1), "greaterThanOrEqual 10"); // greaterThanOrEqual negative tests check(!p1.greaterThanOrEqual(n2), "greaterThanOrEqual 11"); check(!p2.greaterThanOrEqual(n2), "greaterThanOrEqual 12"); check(!n1.greaterThanOrEqual(n2), "greaterThanOrEqual 13"); check(!p1.greaterThanOrEqual(n1), "greaterThanOrEqual 14"); check(!p2.greaterThanOrEqual(n1), "greaterThanOrEqual 15"); check(!p1.greaterThanOrEqual(p2), "greaterThanOrEqual 16"); System.err.println("WindbgAddress: all tests passed successfully."); } }