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     public static void copy(MemoryAddressImpl src, MemoryAddressImpl dst, long size) {
 58         src.checkAccess(0, size, true);
 59         dst.checkAccess(0, size, false);
 60         //check disjoint
 61         long offsetSrc = src.unsafeGetOffset();
 62         long offsetDst = dst.unsafeGetOffset();
 63         Object baseSrc = src.unsafeGetBase();
 64         Object baseDst = dst.unsafeGetBase();
 65         UNSAFE.copyMemory(baseSrc, offsetSrc, baseDst, offsetDst, size);
 66     }
 67 
 68     // MemoryAddress methods
 69 
 70     @Override
 71     public long segmentOffset() {
 72         if (segment() == null) {
 73             throw new UnsupportedOperationException("Address does not have a segment");
 74         }
 75         return offset;
 76     }
 77 
 78     @Override
 79     public long toRawLongValue() {
 80         if (unsafeGetBase() != null) {
 81             throw new UnsupportedOperationException("Not a native address");
 82         }
 83         return unsafeGetOffset();
 84     }
 85 
 86     @Override
 87     public MemorySegment segment() {
 88         return segment != AbstractMemorySegmentImpl.NOTHING ?
 89                 segment : null;
 90     }
 91 
 92     @Override
 93     public MemoryAddress addOffset(long bytes) {
 94         return new MemoryAddressImpl(segment, offset + bytes);
 95     }
 96 
 97     @Override
 98     public MemoryAddress rebase(MemorySegment segment) {
 99         AbstractMemorySegmentImpl segmentImpl = (AbstractMemorySegmentImpl)segment;
100         if (segmentImpl.base() != this.segment.base()) {
101             throw new IllegalArgumentException("Invalid rebase target: " + segment);
102         }
103         return new MemoryAddressImpl((AbstractMemorySegmentImpl)segment,
104                 unsafeGetOffset() - ((MemoryAddressImpl)segment.baseAddress()).unsafeGetOffset());
105     }
106 
107     // MemoryAddressProxy methods
108 
109     public void checkAccess(long offset, long length, boolean readOnly) {
110         segment.checkRange(MemoryAddressProxy.addOffsets(this.offset, offset, this), length, !readOnly);
111     }
112 
113     public long unsafeGetOffset() {
114         return segment.min() + offset;
115     }
116 
117     public Object unsafeGetBase() {
118         return segment.base();
119     }
120 
121     @Override
122     public boolean isSmall() {
123         return segment.isSmall();
124     }
125     // Object methods
126 
127     @Override
128     public int hashCode() {
129         return Objects.hash(unsafeGetBase(), unsafeGetOffset());
130     }
131 
132     @Override
133     public boolean equals(Object that) {
134         if (that instanceof MemoryAddressImpl) {
135             MemoryAddressImpl addr = (MemoryAddressImpl)that;
136             return Objects.equals(unsafeGetBase(), ((MemoryAddressImpl) that).unsafeGetBase()) &&
137                     unsafeGetOffset() == addr.unsafeGetOffset();
138         } else {
139             return false;
140         }
141     }
142 
143     @Override
144     public String toString() {
145         return "MemoryAddress{ region: " + segment + " offset=0x" + Long.toHexString(offset) + " }";
146     }
147 }