1 /*
   2  * Copyright (c) 2018, 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.nicl.types;
  27 
  28 import jdk.internal.nicl.LibrariesHelper;
  29 import jdk.internal.nicl.Util;
  30 
  31 import java.nicl.Libraries;
  32 import java.nicl.metadata.NativeType;
  33 import java.nicl.layout.Address;
  34 import java.nicl.layout.Sequence;
  35 import java.nicl.layout.Value;
  36 import java.nicl.layout.Value.Kind;
  37 import java.nicl.types.*;
  38 
  39 import java.lang.invoke.MethodHandle;
  40 import java.lang.invoke.MethodHandles;
  41 import java.lang.invoke.MethodType;
  42 
  43 /**
  44  * Helper class for references. Defines several reference subclasses, specialized in well-known Java carrier
  45  * types (both primitive and reference types). It also provides factories for common reference types.
  46  */
  47 public final class References {
  48 
  49     private References() {}
  50 
  51     /**
  52      * Reference for primitive carriers. It exposes specialized accessors for getting/setting
  53      * the contents of a reference.
  54      */
  55     static class OfPrimitive implements Reference {
  56 
  57         static final MethodHandle MH_GET_LONG_BITS;
  58         static final MethodHandle MH_SET_LONG_BITS;
  59         
  60         Class<?> carrier;
  61 
  62         static {
  63             try {
  64                 MH_GET_LONG_BITS = MethodHandles.lookup().findStatic(OfPrimitive.class, "getLongBits", MethodType.methodType(long.class, Pointer.class));
  65                 MH_SET_LONG_BITS = MethodHandles.lookup().findStatic(OfPrimitive.class, "setLongBits", MethodType.methodType(void.class, Pointer.class, long.class));
  66             } catch (Throwable ex) {
  67                 throw new IllegalStateException(ex);
  68             }
  69         }
  70 
  71         static long getLongBits(Pointer<?> p2) {
  72             BoundedPointer<?> ptr = (BoundedPointer<?>)p2;
  73             boolean signed = ptr.type.layout() instanceof Value &&
  74                     ((Value)ptr.type.layout()).kind() != Kind.INTEGRAL_UNSIGNED;
  75             return ptr.region.getBits(ptr.offset, ptr.type.layout().bitsSize() / 8, signed);
  76         }
  77 
  78         static void setLongBits(Pointer<?> p2, long value) {
  79             BoundedPointer<?> ptr = (BoundedPointer<?>)p2;
  80             ptr.region.putBits(ptr.offset, ptr.type.layout().bitsSize() / 8, value);
  81         }
  82 
  83         static boolean toBoolean(long value) {
  84             return value != 0;
  85         }
  86 
  87         static long fromBoolean(boolean value) {
  88             return value ? 1 : 0;
  89         }
  90 
  91         public OfPrimitive(Class<?> carrier) {
  92             super();
  93             this.carrier = carrier;
  94         }
  95 
  96         @Override
  97         public MethodHandle getter() {
  98             return MethodHandles.explicitCastArguments(MH_GET_LONG_BITS, MH_GET_LONG_BITS.type().changeReturnType(carrier));
  99         }
 100 
 101         @Override
 102         public MethodHandle setter() {
 103             return MethodHandles.explicitCastArguments(MH_SET_LONG_BITS, MH_SET_LONG_BITS.type().changeParameterType(1, carrier));
 104         }
 105     }
 106 
 107     /**
 108      * A reference for the Java primitive type {@code boolean}.
 109      */
 110     public static class OfBoolean extends OfPrimitive {
 111 
 112         static final MethodHandle MH_TO_BOOLEAN;
 113         static final MethodHandle MH_FROM_BOOLEAN;
 114 
 115         static {
 116             try {
 117                 MH_TO_BOOLEAN = MethodHandles.lookup().findStatic(OfPrimitive.class, "toBoolean", MethodType.methodType(boolean.class, long.class));
 118                 MH_FROM_BOOLEAN = MethodHandles.lookup().findStatic(OfPrimitive.class, "fromBoolean", MethodType.methodType(long.class, boolean.class));
 119             } catch (Throwable ex) {
 120                 throw new IllegalStateException(ex);
 121             }
 122         }
 123 
 124 
 125         OfBoolean() {
 126             super(boolean.class);
 127         }
 128 
 129         @Override
 130         public MethodHandle getter() {
 131             return MethodHandles.filterReturnValue(MH_GET_LONG_BITS, MH_TO_BOOLEAN);
 132         }
 133 
 134         @Override
 135         public MethodHandle setter() {
 136             return MethodHandles.filterArguments(MH_SET_LONG_BITS, 1, MH_FROM_BOOLEAN);
 137         }
 138 
 139         /**
 140          * Read the contents of this reference as a boolean value.
 141          * @return the boolean value.
 142          */
 143         public boolean get(Pointer<?> pointer) {
 144             try {
 145                 return (boolean)getter().invokeExact(pointer);
 146             } catch (Throwable ex) {
 147                 throw new IllegalStateException(ex);
 148             }
 149         }
 150 
 151         /**
 152          * Store a given boolean value in this reference.
 153          * @param value the boolean value.
 154          */
 155         public void set(Pointer<?> pointer, boolean value) {
 156             try {
 157                 setter().invokeExact(pointer, value);
 158             } catch (Throwable ex) {
 159                 throw new IllegalStateException(ex);
 160             }
 161         }
 162     }
 163 
 164     /**
 165      * A reference for the Java primitive type {@code char}.
 166      */
 167     public static class OfChar extends OfPrimitive {
 168 
 169         OfChar() {
 170             super(char.class);
 171         }
 172 
 173         /**
 174          * Read the contents of this reference as a char value.
 175          * @return the char value.
 176          */
 177         public char get(Pointer<?> pointer) {
 178             try {
 179                 return (char)getter().invokeExact(pointer);
 180             } catch (Throwable ex) {
 181                 throw new IllegalStateException(ex);
 182             }
 183         }
 184 
 185         /**
 186          * Store a given char value in this reference.
 187          * @param value the char value.
 188          */
 189         public void set(Pointer<?> pointer, char value) {
 190             try {
 191                 setter().invokeExact(pointer, value);
 192             } catch (Throwable ex) {
 193                 throw new IllegalStateException(ex);
 194             }
 195         }
 196     }
 197 
 198     /**
 199      * A reference for the Java primitive type {@code byte}.
 200      */
 201     public static final class OfByte extends OfPrimitive {
 202 
 203         OfByte() {
 204             super(byte.class);
 205         }
 206 
 207         /**
 208          * Read the contents of this reference as a byte value.
 209          * @return the byte value.
 210          */
 211         public byte get(Pointer<?> pointer) {
 212             try {
 213                 return (byte)getter().invokeExact(pointer);
 214             } catch (Throwable ex) {
 215                 throw new IllegalStateException(ex);
 216             }
 217         }
 218 
 219         /**
 220          * Store a given byte value in this reference.
 221          * @param value the byte value.
 222          */
 223         public void set(Pointer<?> pointer, byte value) {
 224             try {
 225                 setter().invokeExact(pointer, value);
 226             } catch (Throwable ex) {
 227                 throw new IllegalStateException(ex);
 228             }
 229         }
 230     }
 231 
 232     /**
 233      * A reference for the Java primitive type {@code short}.
 234      */
 235     public static class OfShort extends OfPrimitive {
 236 
 237         OfShort() {
 238             super(short.class);
 239         }
 240 
 241         /**
 242          * Read the contents of this reference as a short value.
 243          * @return the short value.
 244          */
 245         public short get(Pointer<?> pointer) {
 246             try {
 247                 return (short)getter().invokeExact(pointer);
 248             } catch (Throwable ex) {
 249                 throw new IllegalStateException(ex);
 250             }
 251         }
 252 
 253         /**
 254          * Store a given short value in this reference.
 255          * @param value the short value.
 256          */
 257         public void set(Pointer<?> pointer, short value) {
 258             try {
 259                 setter().invokeExact(pointer, value);
 260             } catch (Throwable ex) {
 261                 throw new IllegalStateException(ex);
 262             }
 263         }
 264     }
 265 
 266     /**
 267      * A reference for the Java primitive type {@code int}.
 268      */
 269     public static class OfInt extends OfPrimitive {
 270         OfInt() {
 271             super(int.class);
 272         }
 273 
 274         /**
 275          * Read the contents of this reference as an int value.
 276          * @return the int value.
 277          */
 278         public int get(Pointer<?> pointer) {
 279             try {
 280                 return (int)getter().invokeExact(pointer);
 281             } catch (Throwable ex) {
 282                 throw new IllegalStateException(ex);
 283             }
 284         }
 285 
 286         /**
 287          * Store a given int value in this reference.
 288          * @param value the int value.
 289          */
 290         public void set(Pointer<?> pointer, int value) {
 291             try {
 292                 setter().invokeExact(pointer, value);
 293             } catch (Throwable ex) {
 294                 throw new IllegalStateException(ex);
 295             }
 296         }
 297     }
 298 
 299     /**
 300      * A reference for the Java primitive type {@code float}.
 301      */
 302     public static class OfFloat extends OfPrimitive {
 303 
 304         static final MethodHandle MH_TO_FLOAT;
 305         static final MethodHandle MH_FROM_FLOAT;
 306 
 307         static {
 308             try {
 309                 MH_TO_FLOAT = MethodHandles.explicitCastArguments(MethodHandles.lookup().findStatic(Float.class, "intBitsToFloat", MethodType.methodType(float.class, int.class)), MethodType.methodType(float.class, long.class));
 310                 MH_FROM_FLOAT = MethodHandles.explicitCastArguments(MethodHandles.lookup().findStatic(Float.class, "floatToRawIntBits", MethodType.methodType(int.class, float.class)), MethodType.methodType(long.class, float.class));
 311             } catch (Throwable ex) {
 312                 throw new IllegalStateException(ex);
 313             }
 314         }
 315 
 316         OfFloat() {
 317             super(float.class);
 318         }
 319 
 320         @Override
 321         public MethodHandle getter() {
 322             return MethodHandles.filterReturnValue(MH_GET_LONG_BITS, MH_TO_FLOAT);
 323         }
 324 
 325         @Override
 326         public MethodHandle setter() {
 327             return MethodHandles.filterArguments(MH_SET_LONG_BITS, 1, MH_FROM_FLOAT);
 328         }
 329 
 330         /**
 331          * Read the contents of this reference as a float value.
 332          * @return the float value.
 333          */
 334         public float get(Pointer<?> pointer) {
 335             try {
 336                 return (float)getter().invokeExact(pointer);
 337             } catch (Throwable ex) {
 338                 throw new IllegalStateException(ex);
 339             }
 340         }
 341 
 342         /**
 343          * Store a given float value in this reference.
 344          * @param value the float value.
 345          */
 346         public void set(Pointer<?> pointer, float value) {
 347             try {
 348                 setter().invokeExact(pointer, value);
 349             } catch (Throwable ex) {
 350                 throw new IllegalStateException(ex);
 351             }
 352         }
 353     }
 354 
 355     /**
 356      * A reference for the Java primitive type {@code long}.
 357      */
 358     public static class OfLong extends OfPrimitive {
 359 
 360         OfLong() {
 361             super(long.class);
 362         }
 363 
 364         /**
 365          * Read the contents of this reference as a long value.
 366          * @return the long value.
 367          */
 368         public long get(Pointer<?> pointer) {
 369             try {
 370                 return (long)getter().invokeExact(pointer);
 371             } catch (Throwable ex) {
 372                 throw new IllegalStateException(ex);
 373             }
 374         }
 375 
 376         /**
 377          * Store a given long value in this reference.
 378          * @param value the long value.
 379          */
 380         public void set(Pointer<?> pointer, long value) {
 381             try {
 382                 setter().invokeExact(pointer, value);
 383             } catch (Throwable ex) {
 384                 throw new IllegalStateException(ex);
 385             }
 386         }
 387     }
 388 
 389     /**
 390      * A reference for the Java primitive type {@code double}.
 391      */
 392     public static class OfDouble extends OfPrimitive {
 393 
 394         static final MethodHandle MH_TO_DOUBLE;
 395         static final MethodHandle MH_FROM_DOUBLE;
 396 
 397         static {
 398             try {
 399                 MH_TO_DOUBLE = MethodHandles.lookup().findStatic(Double.class, "longBitsToDouble", MethodType.methodType(double.class, long.class));
 400                 MH_FROM_DOUBLE = MethodHandles.lookup().findStatic(Double.class, "doubleToRawLongBits", MethodType.methodType(long.class, double.class));
 401             } catch (Throwable ex) {
 402                 throw new IllegalStateException(ex);
 403             }
 404         }
 405 
 406         OfDouble() {
 407             super(double.class);
 408         }
 409 
 410         @Override
 411         public MethodHandle getter() {
 412             return MethodHandles.filterReturnValue(MH_GET_LONG_BITS, MH_TO_DOUBLE);
 413         }
 414 
 415         @Override
 416         public MethodHandle setter() {
 417             return MethodHandles.filterArguments(MH_SET_LONG_BITS, 1, MH_FROM_DOUBLE);
 418         }
 419 
 420         /**
 421          * Read the contents of this reference as a double value.
 422          * @return the double value.
 423          */
 424         public double get(Pointer<?> pointer) {
 425             try {
 426                 return (double)getter().invokeExact(pointer);
 427             } catch (Throwable ex) {
 428                 throw new IllegalStateException(ex);
 429             }
 430         }
 431 
 432         /**
 433          * Store a given double value in this reference.
 434          * @param value the double value.
 435          */
 436         public void set(Pointer<?> pointer, double value) {
 437             try {
 438                 setter().invokeExact(pointer, value);
 439             } catch (Throwable ex) {
 440                 throw new IllegalStateException(ex);
 441             }
 442         }
 443     }
 444 
 445     /**
 446      * This class models a reference to a Java class type (non-primitive). It provides strongly typed operations
 447      * to get/set the contents of the reference.
 448      * @param <T> the Java type.
 449      */
 450     public static abstract class OfClass<T> implements Reference {
 451 
 452         static final MethodHandle MH_GET;
 453         static final MethodHandle MH_SET;
 454 
 455         static {
 456             try {
 457                 MH_GET = MethodHandles.lookup().findVirtual(OfClass.class, "get", MethodType.methodType(Object.class, Pointer.class));
 458                 MH_SET = MethodHandles.lookup().findVirtual(OfClass.class, "set", MethodType.methodType(void.class, Pointer.class, Object.class));
 459             } catch (Throwable ex) {
 460                 throw new IllegalStateException(ex);
 461             }
 462         }
 463 
 464         protected Class<T> carrier;
 465 
 466         public OfClass(Class<T> carrier) {
 467             super();
 468             this.carrier = carrier;
 469         }
 470 
 471         @Override
 472         public final MethodHandle getter() {
 473             return MH_GET.asType(MH_GET.type().changeReturnType(carrier)).bindTo(this);
 474         }
 475 
 476         @Override
 477         public final MethodHandle setter() {
 478             return MH_SET.asType(MH_SET.type().changeParameterType(2, carrier)).bindTo(this);
 479         }
 480 
 481         /**
 482          * Read the contents of the memory associated with this reference.
 483          * @return a value of type {@code T}.
 484          */
 485         public abstract T get(Pointer<?> pointer);
 486 
 487         /**
 488          * Store a value of type {@code T} in this reference.
 489          * @param value a value of type {@code T}.
 490          */
 491         public abstract void set(Pointer<?> pointer, T value);
 492     }
 493 
 494     /**
 495      * Reference for pointers.
 496      */
 497     public static class OfPointer<X> extends OfClass<Pointer<X>> {
 498 
 499         private final LayoutType<X> pointeeType;
 500 
 501         @SuppressWarnings({"unchecked", "rawtypes"})
 502         public OfPointer(LayoutType<X> pointeeType) {
 503             super((Class) Pointer.class);
 504             this.pointeeType = pointeeType;
 505         }
 506 
 507         @Override
 508         @SuppressWarnings("unchecked")
 509         public Pointer<X> get(Pointer<?> pointer) {
 510             long addr = ofLong.get(pointer);
 511             BoundedPointer<X> rp = addr == 0 ?
 512                     Pointer.nullPointer() :
 513                     new BoundedPointer<>(pointeeType, new BoundedMemoryRegion(null, addr, Long.MAX_VALUE), 0);
 514             return rp;
 515         }
 516 
 517         @Override
 518         public void set(Pointer<?> pointer, Pointer<X> pointerValue) {
 519             try {
 520                 ofLong.set(pointer, pointerValue.addr());
 521             } catch (IllegalAccessException iae) {
 522                 throw new RuntimeException("Access denied", iae);
 523             }
 524         }
 525     }
 526 
 527     /**
 528      * Reference for arrays.
 529      */
 530     public static class OfArray<X> extends OfClass<Array<X>> {
 531 
 532         private final LayoutType<X> elementType;
 533 
 534         @SuppressWarnings({"unchecked", "rawtypes"})
 535         public OfArray(LayoutType<X> elementType) {
 536             super((Class) Array.class);
 537             this.elementType = elementType;
 538         }
 539 
 540         @Override
 541         @SuppressWarnings("unchecked")
 542         public Array<X> get(Pointer<?> pointer) {
 543             Sequence seq = (Sequence)pointer.type().layout();
 544             return new BoundedArray<>((BoundedPointer<X>)pointer.cast(elementType), seq.elementsSize());
 545         }
 546 
 547         @Override
 548         public void set(Pointer<?> pointer, Array<X> arrayValue) {
 549             try {
 550                 MethodHandle elemGetter = elementType.getter();
 551                 MethodHandle elemSetter = elementType.setter();
 552                 Pointer<?> toElemPointer = ((Array<?>)pointer.get()).elementPointer();
 553                 Pointer<X> fromElemPointer = arrayValue.elementPointer();
 554                 // @@@ Perform a bulk copy from the array into the pointers
 555                 // memory region
 556                 Sequence seq = ((Sequence)pointer.type().layout());
 557                 int size = seq.elementsSize();
 558                 for (int i = 0 ; i < size ; i++) {
 559                     Object newVal = elemGetter.invoke(fromElemPointer.offset(i));
 560                     elemSetter.invoke(toElemPointer.offset(i), newVal);
 561                 }
 562             } catch (Throwable ex) {
 563                 throw new IllegalStateException(ex);
 564             }
 565         }
 566     }
 567 
 568     /**
 569      * A reference for native structs.
 570      * @param <T> The Java type associated with the native struct.
 571      */
 572     public static class OfStruct<T extends Struct<T>> extends OfClass<T> {
 573         OfStruct(Class<T> carrier) {
 574             super(carrier);
 575         }
 576 
 577         @Override
 578         @SuppressWarnings("unchecked")
 579         public T get(Pointer<?> pointer) {
 580             Class<?> structClass = LibrariesHelper.getStructImplClass(carrier);
 581             try {
 582                 return (T)structClass.getConstructor(Pointer.class).newInstance(pointer);
 583             } catch (ReflectiveOperationException ex) {
 584                 throw new IllegalStateException(ex);
 585             }
 586         }
 587 
 588         @Override
 589         public void set(Pointer<?> pointer, T t) {
 590             try {
 591                 Util.copy(t.ptr(), pointer, pointer.type().layout().bitsSize() / 8);
 592             } catch (IllegalAccessException iae) {
 593                 throw new RuntimeException("Access denied", iae);
 594             }
 595         }
 596     }
 597 
 598     /**
 599      * Reference factory for the {@code char} primitive type.
 600      */
 601     public static OfChar ofChar = new OfChar(); 
 602 
 603     /**
 604      * Reference factory for the {@code boolean} primitive type.
 605      */
 606     public static OfBoolean ofBoolean = new OfBoolean();
 607 
 608     /**
 609      * Reference factory for the {@code byte} primitive type.
 610      */
 611     public static OfByte ofByte = new OfByte();
 612 
 613     /**
 614      * Reference factory for the {@code short} primitive type.
 615      */
 616     public static OfShort ofShort = new OfShort();
 617 
 618     /**
 619      * Reference factory for the {@code int} primitive type.
 620      */
 621     public static OfInt ofInt = new OfInt();
 622 
 623     /**
 624      * Reference factory for the {@code float} primitive type.
 625      */
 626     public static OfFloat ofFloat = new OfFloat();
 627 
 628     /**
 629      * Reference factory for the {@code long} primitive type.
 630      */
 631     public static OfLong ofLong = new OfLong();
 632 
 633     /**
 634      * Reference for the {@code double} primitive type.
 635      */
 636     public static OfDouble ofDouble = new OfDouble();
 637 
 638     public static <X> OfPointer<X> ofPointer(LayoutType<X> pointeeType) {
 639         return new OfPointer<>(pointeeType);
 640     }
 641 
 642     /**
 643      * Create an array reference factory from a given carrier class.
 644      * @param elementType the array carrier.
 645      * @param <T> the array type.
 646      * @return a reference factory for array references.
 647      * @throws IllegalArgumentException if the carrier is not an array type.
 648      */
 649     public static <T> OfArray<T> ofArray(LayoutType<T> elementType) { return new OfArray<>(elementType); }
 650 
 651     /**
 652      * Create a struct reference factory from a given carrier class.
 653      * @param clazz the native struct carrier.
 654      * @param <T> the native struct type.
 655      * @return a reference factory for native struct references.
 656      * @throws IllegalArgumentException if the carrier is not annotated with the {@link NativeType} annotation.
 657      */
 658     public static <T extends Struct<T>> OfStruct<T> ofStruct(Class<T> clazz) throws IllegalArgumentException {
 659         if (!clazz.isAnnotationPresent(NativeType.class)) {
 660             throw new IllegalArgumentException("Not a native type carrier!");
 661         }
 662         return new OfStruct<>(clazz);
 663     }
 664 }