1 /*
  2  *  Copyright (c) 2020, 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 package jdk.internal.foreign.abi;
 26 
 27 import jdk.incubator.foreign.MemorySegment;
 28 import jdk.incubator.foreign.ValueLayout;
 29 import jdk.internal.foreign.MemoryAddressImpl;
 30 
 31 import java.io.PrintStream;
 32 import java.lang.invoke.VarHandle;
 33 import java.util.HashMap;
 34 import java.util.Map;
 35 
 36 class BufferLayout {
 37     static final VarHandle VH_LONG = ValueLayout.JAVA_LONG.varHandle();
 38 
 39     final long size;
 40     final long arguments_next_pc;
 41     final long stack_args_bytes;
 42     final long stack_args;
 43 
 44     // read by JNI
 45     final long[] input_type_offsets;
 46     final long[] output_type_offsets;
 47 
 48     private final Map<jdk.internal.foreign.abi.VMStorage, Long> argOffsets;
 49     private final Map<jdk.internal.foreign.abi.VMStorage, Long> retOffsets;
 50 
 51     private BufferLayout(long size, long arguments_next_pc, long stack_args_bytes, long stack_args,
 52                          long[] input_type_offsets, long[] output_type_offsets,
 53                          Map<jdk.internal.foreign.abi.VMStorage, Long> argOffsets, Map<jdk.internal.foreign.abi.VMStorage, Long> retOffsets) {
 54         this.size = size;
 55         this.arguments_next_pc = arguments_next_pc;
 56         this.stack_args_bytes = stack_args_bytes;
 57         this.stack_args = stack_args;
 58         this.input_type_offsets = input_type_offsets;
 59         this.output_type_offsets = output_type_offsets;
 60         this.argOffsets = argOffsets;
 61         this.retOffsets = retOffsets;
 62     }
 63 
 64     static BufferLayout of(ABIDescriptor abi) {
 65         long offset = 0;
 66 
 67         offset = SharedUtils.alignUp(offset, 8);
 68         long arguments_next_pc = offset;
 69         offset += 8;
 70 
 71         offset = SharedUtils.alignUp(offset, 8);
 72         long stack_args_bytes = offset;
 73         offset += 8;
 74 
 75         offset = SharedUtils.alignUp(offset, 8);
 76         long stack_args = offset;
 77         offset += 8;
 78 
 79         Map<jdk.internal.foreign.abi.VMStorage, Long> argOffsets = new HashMap<>();
 80         long[] input_type_offsets = new long[abi.inputStorage.length];
 81         for (int i = 0; i < abi.inputStorage.length; i++) {
 82             long size = abi.arch.typeSize(i);
 83             offset = SharedUtils.alignUp(offset, size);
 84             input_type_offsets[i] = offset;
 85             for (jdk.internal.foreign.abi.VMStorage store : abi.inputStorage[i]) {
 86                 argOffsets.put(store, offset);
 87                 offset += size;
 88             }
 89         }
 90 
 91         Map<jdk.internal.foreign.abi.VMStorage, Long> retOffsets = new HashMap<>();
 92         long[] output_type_offsets = new long[abi.outputStorage.length];
 93         for (int i = 0; i < abi.outputStorage.length; i++) {
 94             long size = abi.arch.typeSize(i);
 95             offset = SharedUtils.alignUp(offset, size);
 96             output_type_offsets[i] = offset;
 97             for (jdk.internal.foreign.abi.VMStorage store : abi.outputStorage[i]) {
 98                 retOffsets.put(store, offset);
 99                 offset += size;
100             }
101         }
102 
103         return new BufferLayout(offset, arguments_next_pc, stack_args_bytes, stack_args,
104                 input_type_offsets, output_type_offsets, argOffsets, retOffsets);
105     }
106 
107     long argOffset(jdk.internal.foreign.abi.VMStorage storage) {
108         return argOffsets.get(storage);
109     }
110 
111     long retOffset(jdk.internal.foreign.abi.VMStorage storage) {
112         return retOffsets.get(storage);
113     }
114 
115     private static String getLongString(MemorySegment buffer, long offset) {
116         return Long.toHexString((long) VH_LONG.get(buffer.asSlice(offset)));
117     }
118 
119     private void dumpValues(jdk.internal.foreign.abi.Architecture arch, MemorySegment buff, PrintStream stream,
120                                    Map<jdk.internal.foreign.abi.VMStorage, Long> offsets) {
121         for (var entry : offsets.entrySet()) {
122             VMStorage storage = entry.getKey();
123             stream.print(storage.name());
124             stream.print("={ ");
125             MemorySegment start = buff.asSlice(entry.getValue());
126             for (int i = 0; i < arch.typeSize(storage.type()) / 8; i += 8) {
127                 stream.print(getLongString(start, i));
128                 stream.print(" ");
129             }
130             stream.println("}");
131         }
132         long stack_ptr = (long) VH_LONG.get(buff.asSlice(stack_args));
133         long stack_bytes = (long) VH_LONG.get(buff.asSlice(stack_args_bytes));
134         MemorySegment stackArgs = MemoryAddressImpl.ofLongUnchecked(stack_ptr, stack_bytes);
135         stream.println("Stack {");
136         for (int i = 0; i < stack_bytes / 8; i += 8) {
137             stream.printf("    @%d: %s%n", i, getLongString(stackArgs, i));
138         }
139         stream.println("}");
140     }
141 
142     void dump(Architecture arch, MemorySegment buff, PrintStream stream) {
143         stream.println("Next PC: " + getLongString(buff, arguments_next_pc));
144         stream.println("Stack args bytes: " + getLongString(buff, stack_args_bytes));
145         stream.println("Stack args ptr: " + getLongString(buff, stack_args));
146 
147         stream.println("Arguments:");
148         dumpValues(arch, buff, stream, argOffsets);
149         stream.println("Returns:");
150         dumpValues(arch, buff, stream, retOffsets);
151     }
152 }