1 /*
 2  * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
 3  * Copyright (c) 2019, 2021, Arm Limited. All rights reserved.
 4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 5  *
 6  * This code is free software; you can redistribute it and/or modify it
 7  * under the terms of the GNU General Public License version 2 only, as
 8  * published by the Free Software Foundation.  Oracle designates this
 9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 package jdk.internal.foreign.abi.aarch64.linux;
27 
28 import jdk.incubator.foreign.CLinker;
29 import jdk.incubator.foreign.FunctionDescriptor;
30 import jdk.incubator.foreign.MemoryAddress;
31 import jdk.incubator.foreign.MemorySegment;
32 import jdk.incubator.foreign.NativeSymbol;
33 import jdk.incubator.foreign.ResourceScope;
34 import jdk.incubator.foreign.VaList;
35 import jdk.internal.foreign.abi.SharedUtils;
36 import jdk.internal.foreign.abi.aarch64.CallArranger;
37 
38 import java.lang.invoke.MethodHandle;
39 import java.lang.invoke.MethodHandles;
40 import java.lang.invoke.MethodType;
41 import java.util.Objects;
42 import java.util.function.Consumer;
43 
44 /**
45  * ABI implementation based on ARM document "Procedure Call Standard for
46  * the ARM 64-bit Architecture".
47  */
48 public final class LinuxAArch64Linker implements CLinker {
49     private static LinuxAArch64Linker instance;
50 
51     static final long ADDRESS_SIZE = 64; // bits
52 
53     public static LinuxAArch64Linker getInstance() {
54         if (instance == null) {
55             instance = new LinuxAArch64Linker();
56         }
57         return instance;
58     }
59 
60     @Override
61     public final MethodHandle downcallHandle(FunctionDescriptor function) {
62         Objects.requireNonNull(function);
63         MethodType type = SharedUtils.inferMethodType(function, false);
64         MethodHandle handle = CallArranger.arrangeDowncall(type, function);
65         if (!type.returnType().equals(MemorySegment.class)) {
66             // not returning segment, just insert a throwing allocator
67             handle = MethodHandles.insertArguments(handle, 1, SharedUtils.THROWING_ALLOCATOR);
68         }
69         return SharedUtils.wrapDowncall(handle, function);
70     }
71 
72     @Override
73     public final NativeSymbol upcallStub(MethodHandle target, FunctionDescriptor function, ResourceScope scope) {
74         Objects.requireNonNull(scope);
75         Objects.requireNonNull(target);
76         Objects.requireNonNull(function);
77         SharedUtils.checkExceptions(target);
78         MethodType type = SharedUtils.inferMethodType(function, true);
79         if (!type.equals(target.type())) {
80             throw new IllegalArgumentException("Wrong method handle type: " + target.type());
81         }
82         return CallArranger.arrangeUpcall(target, target.type(), function, scope);
83     }
84 
85     public static VaList newVaList(Consumer<VaList.Builder> actions, ResourceScope scope) {
86         LinuxAArch64VaList.Builder builder = LinuxAArch64VaList.builder(scope);
87         actions.accept(builder);
88         return builder.build();
89     }
90 
91     public static VaList newVaListOfAddress(MemoryAddress ma, ResourceScope scope) {
92         return LinuxAArch64VaList.ofAddress(ma, scope);
93     }
94 
95     public static VaList emptyVaList() {
96         return LinuxAArch64VaList.empty();
97     }
98 
99 }