1 /*
  2  *  Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  3  *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  *  This code is free software; you can redistribute it and/or modify it
  6  *  under the terms of the GNU General Public License version 2 only, as
  7  *  published by the Free Software Foundation.  Oracle designates this
  8  *  particular file as subject to the "Classpath" exception as provided
  9  *  by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  *  This code is distributed in the hope that it will be useful, but WITHOUT
 12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  *  version 2 for more details (a copy is included in the LICENSE file that
 15  *  accompanied this code).
 16  *
 17  *  You should have received a copy of the GNU General Public License version
 18  *  2 along with this work; if not, write to the Free Software Foundation,
 19  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  *  or visit www.oracle.com if you need additional information or have any
 23  *  questions.
 24  *
 25  */
 26 package jdk.internal.foreign;
 27 
 28 import jdk.internal.access.foreign.MemoryAddressProxy;
 29 import jdk.internal.misc.Unsafe;
 30 
 31 import jdk.incubator.foreign.MemoryAddress;
 32 import jdk.incubator.foreign.MemorySegment;
 33 
 34 import java.util.Objects;
 35 
 36 /**
 37  * This class provides an immutable implementation for the {@code MemoryAddress} interface. This class contains information
 38  * about the segment this address is associated with, as well as an offset into such segment.
 39  */
 40 public final class MemoryAddressImpl implements MemoryAddress, MemoryAddressProxy {
 41 
 42     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
 43 
 44     private final AbstractMemorySegmentImpl segment;
 45     private final long offset;
 46 
 47     public MemoryAddressImpl(long offset) {
 48         this.segment = AbstractMemorySegmentImpl.NOTHING;
 49         this.offset = offset;
 50     }
 51 
 52     public MemoryAddressImpl(AbstractMemorySegmentImpl segment, long offset) {
 53         this.segment = Objects.requireNonNull(segment);
 54         this.offset = offset;
 55     }
 56 
 57     // MemoryAddress methods
 58 
 59     @Override
 60     public long segmentOffset() {
 61         if (segment() == null) {
 62             throw new UnsupportedOperationException("Address does not have a segment");
 63         }
 64         return offset;
 65     }
 66 
 67     @Override
 68     public long toRawLongValue() {
 69         if (unsafeGetBase() != null) {
 70             throw new UnsupportedOperationException("Not a native address");
 71         }
 72         return unsafeGetOffset();
 73     }
 74 
 75     @Override
 76     public MemorySegment segment() {
 77         return segment != AbstractMemorySegmentImpl.NOTHING ?
 78                 segment : null;
 79     }
 80 
 81     @Override
 82     public MemoryAddress addOffset(long bytes) {
 83         return new MemoryAddressImpl(segment, offset + bytes);
 84     }
 85 
 86     @Override
 87     public MemoryAddress rebase(MemorySegment segment) {
 88         AbstractMemorySegmentImpl segmentImpl = (AbstractMemorySegmentImpl)segment;
 89         if (segmentImpl.base() != this.segment.base()) {
 90             throw new IllegalArgumentException("Invalid rebase target: " + segment);
 91         }
 92         return new MemoryAddressImpl((AbstractMemorySegmentImpl)segment,
 93                 unsafeGetOffset() - ((MemoryAddressImpl)segment.baseAddress()).unsafeGetOffset());
 94     }
 95 
 96     // MemoryAddressProxy methods
 97 
 98     public void checkAccess(long offset, long length, boolean readOnly) {
 99         segment.checkRange(MemoryAddressProxy.addOffsets(this.offset, offset, this), length, !readOnly);
100     }
101 
102     public long unsafeGetOffset() {
103         return segment.min() + offset;
104     }
105 
106     public Object unsafeGetBase() {
107         return segment.base();
108     }
109 
110     @Override
111     public boolean isSmall() {
112         return segment.isSmall();
113     }
114     // Object methods
115 
116     @Override
117     public int hashCode() {
118         return Objects.hash(unsafeGetBase(), unsafeGetOffset());
119     }
120 
121     @Override
122     public boolean equals(Object that) {
123         if (that instanceof MemoryAddressImpl) {
124             MemoryAddressImpl addr = (MemoryAddressImpl)that;
125             return Objects.equals(unsafeGetBase(), ((MemoryAddressImpl) that).unsafeGetBase()) &&
126                     unsafeGetOffset() == addr.unsafeGetOffset();
127         } else {
128             return false;
129         }
130     }
131 
132     @Override
133     public String toString() {
134         return "MemoryAddress{ region: " + segment + " offset=0x" + Long.toHexString(offset) + " }";
135     }
136 }