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.incubator.foreign;
  27 
  28 import java.lang.constant.ClassDesc;
  29 import java.lang.constant.ConstantDesc;
  30 import java.lang.constant.ConstantDescs;
  31 import java.lang.constant.DirectMethodHandleDesc;
  32 import java.lang.constant.DynamicConstantDesc;
  33 import java.lang.constant.MethodHandleDesc;
  34 import java.lang.constant.MethodTypeDesc;
  35 import java.nio.ByteOrder;
  36 import java.util.Objects;
  37 import java.util.Optional;
  38 import java.util.OptionalLong;
  39 
  40 abstract class AbstractLayout implements MemoryLayout {
  41     private final OptionalLong size;
  42     final long alignment;
  43     private final Optional<String> name;
  44 
  45     public AbstractLayout(OptionalLong size, long alignment, Optional<String> name) {
  46         this.size = size;
  47         this.alignment = alignment;
  48         this.name = name;
  49     }
  50 
  51     Optional<String> optName() {
  52         return name;
  53     }
  54 
  55     @Override
  56     public AbstractLayout withName(String name) {
  57         return dup(alignment, Optional.of(name));
  58     }
  59 
  60     @Override
  61     public final Optional<String> name() {
  62         return name;
  63     }
  64 
  65     abstract AbstractLayout dup(long alignment, Optional<String> name);
  66 
  67     @Override
  68     public AbstractLayout withBitAlignment(long alignmentBits) {
  69         checkAlignment(alignmentBits);
  70         return dup(alignmentBits, name);
  71     }
  72 
  73     void checkAlignment(long alignmentBitCount) {
  74         if (((alignmentBitCount & (alignmentBitCount - 1)) != 0L) || //alignment must be a power of two
  75                 (alignmentBitCount < 8)) { //alignment must be greater than 8
  76             throw new IllegalArgumentException("Invalid alignment: " + alignmentBitCount);
  77         }
  78     }
  79 
  80     static void checkSize(long size) {
  81         checkSize(size, false);
  82     }
  83 
  84     static void checkSize(long size, boolean includeZero) {
  85         if (size < 0 || (!includeZero && size == 0)) {
  86             throw new IllegalArgumentException("Invalid size for layout: " + size);
  87         }
  88     }
  89 
  90     @Override
  91     public final long bitAlignment() {
  92         return alignment;
  93     }
  94 
  95     @Override
  96     public long bitSize() {
  97         return size.orElseThrow(this::badSizeException);
  98     }
  99 
 100     static OptionalLong optSize(MemoryLayout layout) {
 101         return ((AbstractLayout)layout).size;
 102     }
 103 
 104     private UnsupportedOperationException badSizeException() {
 105         return new UnsupportedOperationException("Cannot compute size of a layout which is, or depends on a sequence layout with unspecified size");
 106     }
 107 
 108     String decorateLayoutString(String s) {
 109         if (name.isPresent()) {
 110             s = String.format("%s(%s)", s, name.get());
 111         }
 112         if (!hasNaturalAlignment()) {
 113             s = alignment + "%" + s;
 114         }
 115         return s;
 116     }
 117 
 118     boolean hasNaturalAlignment() {
 119         return size.isPresent() && size.getAsLong() == alignment;
 120     }
 121 
 122     @Override
 123     public int hashCode() {
 124         return name.hashCode() << Long.hashCode(alignment);
 125     }
 126 
 127     @Override
 128     public boolean equals(Object other) {
 129         if (this == other) {
 130             return true;
 131         }
 132 
 133         if (!(other instanceof AbstractLayout)) {
 134             return false;
 135         }
 136 
 137         return Objects.equals(name, ((AbstractLayout)other).name) &&
 138                 Objects.equals(alignment, ((AbstractLayout)other).alignment);
 139     }
 140 
 141     /*** Helper constants for implementing Layout::describeConstable ***/
 142 
 143     public static final DirectMethodHandleDesc BSM_GET_STATIC_FINAL
 144             = ConstantDescs.ofConstantBootstrap(ConstantDescs.CD_ConstantBootstraps, "getStaticFinal",
 145             ConstantDescs.CD_Object, ConstantDescs.CD_Class);
 146 
 147     static final ClassDesc CD_LAYOUT = MemoryLayout.class.describeConstable().get();
 148 
 149     static final ClassDesc CD_VALUE_LAYOUT = ValueLayout.class.describeConstable().get();
 150 
 151     static final ClassDesc CD_SEQUENCE_LAYOUT = SequenceLayout.class.describeConstable().get();
 152 
 153     static final ClassDesc CD_GROUP_LAYOUT = GroupLayout.class.describeConstable().get();
 154 
 155     static final ClassDesc CD_BYTEORDER = ByteOrder.class.describeConstable().get();
 156 
 157     static final ConstantDesc BIG_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "BIG_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);
 158 
 159     static final ConstantDesc LITTLE_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "LITTLE_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);
 160 
 161     static final MethodHandleDesc MH_PADDING = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofPaddingBits",
 162                 MethodTypeDesc.of(CD_LAYOUT, ConstantDescs.CD_long));
 163 
 164     static final MethodHandleDesc MH_VALUE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofValueBits",
 165                 MethodTypeDesc.of(CD_VALUE_LAYOUT, ConstantDescs.CD_long, CD_BYTEORDER));
 166 
 167     static final MethodHandleDesc MH_SIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofSequence",
 168                 MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, ConstantDescs.CD_long, CD_LAYOUT));
 169 
 170     static final MethodHandleDesc MH_UNSIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofSequence",
 171                 MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, CD_LAYOUT));
 172 
 173     static final MethodHandleDesc MH_STRUCT = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofStruct",
 174                 MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_LAYOUT.arrayType()));
 175 
 176     static final MethodHandleDesc MH_UNION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofUnion",
 177                 MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_LAYOUT.arrayType()));
 178 }