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.incubator.foreign.MemoryAddress;
 29 import jdk.incubator.foreign.MemorySegment;
 30 import jdk.internal.reflect.CallerSensitive;
 31 import jdk.internal.reflect.Reflection;
 32 
 33 import jdk.incubator.foreign.ResourceScope;
 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 {
 41 
 42     private final AbstractMemorySegmentImpl segment;
 43     private final long offset;
 44 
 45     public MemoryAddressImpl(AbstractMemorySegmentImpl segment, long offset) {
 46         this.segment = segment;
 47         this.offset = offset;
 48     }
 49 
 50     Object base() {
 51         return segment != null ? segment.base() : null;
 52     }
 53 
 54     long offset() {
 55         return segment != null ?
 56                 segment.min() + offset : offset;
 57     }
 58 
 59     // MemoryAddress methods
 60 
 61     @Override
 62     public ResourceScope scope() {
 63         return segment != null ?
 64                 segment.scope() : ResourceScope.globalScope();
 65     }
 66 
 67     @Override
 68     public MemoryAddress addOffset(long offset) {
 69         return new MemoryAddressImpl(segment, this.offset + offset);
 70     }
 71 
 72     @Override
 73     public long segmentOffset(MemorySegment segment) {
 74         Objects.requireNonNull(segment);
 75         AbstractMemorySegmentImpl segmentImpl = (AbstractMemorySegmentImpl)segment;
 76         if (segmentImpl.base() != base()) {
 77             throw new IllegalArgumentException("Incompatible segment: " + segment);
 78         }
 79         return offset() - segmentImpl.min();
 80     }
 81 
 82     @Override
 83     public boolean isNative() {
 84         return base() == null;
 85     }
 86 
 87     @Override
 88     public long toRawLongValue() {
 89         if (segment != null) {
 90             if (segment.base() != null) {
 91                 throw new UnsupportedOperationException("Not a native address");
 92             }
 93             segment.checkValidState();
 94         }
 95         return offset();
 96     }
 97 
 98     // Object methods
 99 
100     @Override
101     public int hashCode() {
102         return Objects.hash(base(), offset());
103     }
104 
105     @Override
106     public boolean equals(Object that) {
107         if (that instanceof MemoryAddressImpl) {
108             MemoryAddressImpl addr = (MemoryAddressImpl)that;
109             return Objects.equals(base(), addr.base()) &&
110                     offset() == addr.offset();
111         } else {
112             return false;
113         }
114     }
115 
116     @Override
117     public String toString() {
118         return "MemoryAddress{ base: " + base() + " offset=0x" + Long.toHexString(offset()) + " }";
119     }
120 
121     @Override
122     @CallerSensitive
123     public final MemorySegment asSegment(long bytesSize, ResourceScope scope) {
124         Reflection.ensureNativeAccess(Reflection.getCallerClass());
125         return asSegment(bytesSize, null, scope);
126     }
127 
128     @Override
129     @CallerSensitive
130     public final MemorySegment asSegment(long bytesSize, Runnable cleanupAction, ResourceScope scope) {
131         Reflection.ensureNativeAccess(Reflection.getCallerClass());
132         Objects.requireNonNull(scope);
133         if (bytesSize <= 0) {
134             throw new IllegalArgumentException("Invalid size : " + bytesSize);
135         }
136         return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(this, bytesSize,
137                 cleanupAction,
138                 (ResourceScopeImpl) scope);
139     }
140 
141     public static MemorySegment ofLongUnchecked(long value) {
142         return ofLongUnchecked(value, Long.MAX_VALUE);
143     }
144 
145     public static MemorySegment ofLongUnchecked(long value, long byteSize, ResourceScopeImpl resourceScope) {
146         return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(MemoryAddress.ofLong(value), byteSize, null, resourceScope);
147     }
148 
149     public static MemorySegment ofLongUnchecked(long value, long byteSize) {
150         return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(MemoryAddress.ofLong(value), byteSize, null, ResourceScopeImpl.GLOBAL);
151     }
152 }