001/* 002 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.truffle.hotspot.nfi; 024 025import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; 026 027import java.util.*; 028 029import jdk.internal.jvmci.common.*; 030import jdk.internal.jvmci.hotspot.*; 031import jdk.internal.jvmci.meta.*; 032 033import com.oracle.graal.compiler.common.type.*; 034import com.oracle.graal.hotspot.meta.*; 035import com.oracle.graal.nodes.*; 036import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; 037import com.oracle.graal.nodes.extended.*; 038import com.oracle.graal.nodes.java.*; 039import com.oracle.graal.nodes.memory.address.*; 040import com.oracle.graal.nodes.virtual.*; 041import com.oracle.graal.word.nodes.*; 042 043/** 044 * Utility creating a graph for a stub used to call a native function. 045 */ 046public class NativeCallStubGraphBuilder { 047 048 /** 049 * Creates a graph for a stub used to call a native function. 050 * 051 * @param functionPointer a native function pointer 052 * @param returnType the type of the return value 053 * @param argumentTypes the types of the arguments 054 * @return the graph that represents the call stub 055 */ 056 public static StructuredGraph getGraph(HotSpotProviders providers, RawNativeCallNodeFactory factory, long functionPointer, Class<?> returnType, Class<?>... argumentTypes) { 057 try { 058 ResolvedJavaMethod method = providers.getMetaAccess().lookupJavaMethod(NativeCallStubGraphBuilder.class.getMethod("libCall", Object.class, Object.class, Object.class)); 059 StructuredGraph g = new StructuredGraph(method, AllowAssumptions.NO); 060 ParameterNode arg0 = g.unique(new ParameterNode(0, StampFactory.forKind(Kind.Object))); 061 ParameterNode arg1 = g.unique(new ParameterNode(1, StampFactory.forKind(Kind.Object))); 062 ParameterNode arg2 = g.unique(new ParameterNode(2, StampFactory.forKind(Kind.Object))); 063 FrameState frameState = g.add(new FrameState(null, method, 0, Arrays.asList(new ValueNode[]{arg0, arg1, arg2}), 3, 0, false, false, null, new ArrayList<EscapeObjectState>())); 064 g.start().setStateAfter(frameState); 065 List<ValueNode> parameters = new ArrayList<>(); 066 FixedWithNextNode fixedWithNext = getParameters(g, arg0, argumentTypes.length, argumentTypes, parameters, providers); 067 JavaConstant functionPointerNode = JavaConstant.forLong(functionPointer); 068 069 ValueNode[] arguments = new ValueNode[parameters.size()]; 070 071 for (int i = 0; i < arguments.length; i++) { 072 arguments[i] = parameters.get(i); 073 } 074 075 FixedWithNextNode callNode = g.add(factory.createRawCallNode(getKind(returnType), functionPointerNode, arguments)); 076 077 if (fixedWithNext == null) { 078 g.start().setNext(callNode); 079 } else { 080 fixedWithNext.setNext(callNode); 081 } 082 083 // box result 084 BoxNode boxedResult; 085 if (callNode.getKind() != Kind.Void) { 086 if (callNode.getKind() == Kind.Object) { 087 throw new IllegalArgumentException("Return type not supported: " + returnType.getName()); 088 } 089 ResolvedJavaType type = providers.getMetaAccess().lookupJavaType(callNode.getKind().toBoxedJavaClass()); 090 boxedResult = g.add(new BoxNode(callNode, type, callNode.getKind())); 091 } else { 092 boxedResult = g.add(new BoxNode(ConstantNode.forLong(0, g), providers.getMetaAccess().lookupJavaType(Long.class), Kind.Long)); 093 } 094 095 callNode.setNext(boxedResult); 096 ReturnNode returnNode = g.add(new ReturnNode(boxedResult)); 097 boxedResult.setNext(returnNode); 098 return g; 099 } catch (NoSuchMethodException e) { 100 throw JVMCIError.shouldNotReachHere("Call Stub method not found"); 101 } 102 } 103 104 private static FixedWithNextNode getParameters(StructuredGraph g, ParameterNode argumentsArray, int numArgs, Class<?>[] argumentTypes, List<ValueNode> args, HotSpotProviders providers) { 105 assert numArgs == argumentTypes.length; 106 FixedWithNextNode last = null; 107 for (int i = 0; i < numArgs; i++) { 108 // load boxed array element: 109 LoadIndexedNode boxedElement = g.add(new LoadIndexedNode(argumentsArray, ConstantNode.forInt(i, g), Kind.Object)); 110 if (i == 0) { 111 g.start().setNext(boxedElement); 112 last = boxedElement; 113 } else { 114 last.setNext(boxedElement); 115 last = boxedElement; 116 } 117 Class<?> type = argumentTypes[i]; 118 Kind kind = getKind(type); 119 if (kind == Kind.Object) { 120 // array value 121 Kind arrayElementKind = getElementKind(type); 122 HotSpotJVMCIRuntimeProvider jvmciRuntime = runtime().getJVMCIRuntime(); 123 int displacement = jvmciRuntime.getArrayBaseOffset(arrayElementKind); 124 AddressNode arrayAddress = g.unique(new OffsetAddressNode(boxedElement, ConstantNode.forLong(displacement, g))); 125 WordCastNode cast = g.add(WordCastNode.addressToWord(arrayAddress, providers.getWordTypes().getWordKind())); 126 last.setNext(cast); 127 last = cast; 128 args.add(cast); 129 } else { 130 // boxed primitive value 131 try { 132 ResolvedJavaField field = providers.getMetaAccess().lookupJavaField(kind.toBoxedJavaClass().getDeclaredField("value")); 133 LoadFieldNode loadFieldNode = g.add(new LoadFieldNode(boxedElement, field)); 134 last.setNext(loadFieldNode); 135 last = loadFieldNode; 136 args.add(loadFieldNode); 137 } catch (NoSuchFieldException e) { 138 throw new JVMCIError(e); 139 } 140 } 141 } 142 return last; 143 } 144 145 public static Kind getElementKind(Class<?> clazz) { 146 Class<?> componentType = clazz.getComponentType(); 147 if (componentType == null) { 148 throw new IllegalArgumentException("Parameter type not supported: " + clazz); 149 } 150 if (componentType.isPrimitive()) { 151 return Kind.fromJavaClass(componentType); 152 } 153 throw new IllegalArgumentException("Parameter type not supported: " + clazz); 154 } 155 156 private static Kind getKind(Class<?> clazz) { 157 if (clazz == int.class || clazz == Integer.class) { 158 return Kind.Int; 159 } else if (clazz == long.class || clazz == Long.class) { 160 return Kind.Long; 161 } else if (clazz == char.class || clazz == Character.class) { 162 return Kind.Char; 163 } else if (clazz == byte.class || clazz == Byte.class) { 164 return Kind.Byte; 165 } else if (clazz == float.class || clazz == Float.class) { 166 return Kind.Float; 167 } else if (clazz == double.class || clazz == Double.class) { 168 return Kind.Double; 169 } else if (clazz == int[].class || clazz == long[].class || clazz == char[].class || clazz == byte[].class || clazz == float[].class || clazz == double[].class) { 170 return Kind.Object; 171 } else if (clazz == void.class) { 172 return Kind.Void; 173 } else { 174 throw new IllegalArgumentException("Type not supported: " + clazz); 175 } 176 } 177 178 @SuppressWarnings("unused") 179 public static Object libCall(Object argLoc, Object unused1, Object unused2) { 180 throw JVMCIError.shouldNotReachHere("GNFI libCall method must not be called"); 181 } 182}