001/*
002 * Copyright (c) 2011, 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 jdk.internal.jvmci.hotspot;
024
025import java.util.*;
026
027import jdk.internal.jvmci.common.*;
028import jdk.internal.jvmci.meta.*;
029
030/**
031 * Represents a method signature.
032 */
033public class HotSpotSignature implements Signature {
034
035    private final List<String> parameters = new ArrayList<>();
036    private final String returnType;
037    private final String originalString;
038    private ResolvedJavaType[] parameterTypes;
039    private ResolvedJavaType returnTypeCache;
040    private final HotSpotJVMCIRuntimeProvider runtime;
041
042    public HotSpotSignature(HotSpotJVMCIRuntimeProvider runtime, String signature) {
043        this.runtime = runtime;
044        assert signature.length() > 0;
045        this.originalString = signature;
046
047        if (signature.charAt(0) == '(') {
048            int cur = 1;
049            while (cur < signature.length() && signature.charAt(cur) != ')') {
050                int nextCur = parseSignature(signature, cur);
051                parameters.add(signature.substring(cur, nextCur));
052                cur = nextCur;
053            }
054
055            cur++;
056            int nextCur = parseSignature(signature, cur);
057            returnType = signature.substring(cur, nextCur);
058            assert nextCur == signature.length();
059        } else {
060            returnType = null;
061        }
062    }
063
064    public HotSpotSignature(HotSpotJVMCIRuntimeProvider runtime, ResolvedJavaType returnType, ResolvedJavaType... parameterTypes) {
065        this.runtime = runtime;
066        this.parameterTypes = parameterTypes.clone();
067        this.returnTypeCache = returnType;
068        this.returnType = returnType.getName();
069        StringBuilder sb = new StringBuilder("(");
070        for (JavaType type : parameterTypes) {
071            parameters.add(type.getName());
072            sb.append(type.getName());
073        }
074        sb.append(")").append(returnType.getName());
075        this.originalString = sb.toString();
076        assert new HotSpotSignature(runtime, originalString).equals(this);
077    }
078
079    private static int parseSignature(String signature, int start) {
080        int cur = start;
081        char first;
082        do {
083            first = signature.charAt(cur++);
084        } while (first == '[');
085
086        switch (first) {
087            case 'L':
088                while (signature.charAt(cur) != ';') {
089                    cur++;
090                }
091                cur++;
092                break;
093            case 'V':
094            case 'I':
095            case 'B':
096            case 'C':
097            case 'D':
098            case 'F':
099            case 'J':
100            case 'S':
101            case 'Z':
102                break;
103            default:
104                throw new JVMCIError("Invalid character at index %d in signature: %s", cur, signature);
105        }
106        return cur;
107    }
108
109    @Override
110    public int getParameterCount(boolean withReceiver) {
111        return parameters.size() + (withReceiver ? 1 : 0);
112    }
113
114    @Override
115    public Kind getParameterKind(int index) {
116        return Kind.fromTypeString(parameters.get(index));
117    }
118
119    private static boolean checkValidCache(ResolvedJavaType type, ResolvedJavaType accessingClass) {
120        assert accessingClass != null;
121        if (type == null) {
122            return false;
123        } else if (type instanceof HotSpotResolvedObjectTypeImpl) {
124            return ((HotSpotResolvedObjectTypeImpl) type).isDefinitelyResolvedWithRespectTo(accessingClass);
125        }
126        return true;
127    }
128
129    private static JavaType getUnresolvedOrPrimitiveType(HotSpotJVMCIRuntimeProvider runtime, String name) {
130        if (name.length() == 1) {
131            Kind kind = Kind.fromPrimitiveOrVoidTypeChar(name.charAt(0));
132            return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(kind.toJavaClass());
133        }
134        return new HotSpotUnresolvedJavaType(name, runtime);
135    }
136
137    @Override
138    public JavaType getParameterType(int index, ResolvedJavaType accessingClass) {
139        if (accessingClass == null) {
140            // Caller doesn't care about resolution context so return an unresolved
141            // or primitive type (primitive type resolution is context free)
142            return getUnresolvedOrPrimitiveType(runtime, parameters.get(index));
143        }
144        if (parameterTypes == null) {
145            parameterTypes = new ResolvedJavaType[parameters.size()];
146        }
147
148        ResolvedJavaType type = parameterTypes[index];
149        if (!checkValidCache(type, accessingClass)) {
150            JavaType result = runtime.lookupType(parameters.get(index), (HotSpotResolvedObjectType) accessingClass, false);
151            if (result instanceof ResolvedJavaType) {
152                type = (ResolvedJavaType) result;
153                parameterTypes[index] = type;
154            } else {
155                return result;
156            }
157        }
158        return type;
159    }
160
161    @Override
162    public String toMethodDescriptor() {
163        assert originalString.equals(Signature.super.toMethodDescriptor());
164        return originalString;
165    }
166
167    @Override
168    public Kind getReturnKind() {
169        return Kind.fromTypeString(returnType);
170    }
171
172    @Override
173    public JavaType getReturnType(ResolvedJavaType accessingClass) {
174        if (accessingClass == null) {
175            // Caller doesn't care about resolution context so return an unresolved
176            // or primitive type (primitive type resolution is context free)
177            return getUnresolvedOrPrimitiveType(runtime, returnType);
178        }
179        if (!checkValidCache(returnTypeCache, accessingClass)) {
180            JavaType result = runtime.lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false);
181            if (result instanceof ResolvedJavaType) {
182                returnTypeCache = (ResolvedJavaType) result;
183            } else {
184                return result;
185            }
186        }
187        return returnTypeCache;
188    }
189
190    @Override
191    public String toString() {
192        return "HotSpotSignature<" + originalString + ">";
193    }
194
195    @Override
196    public boolean equals(Object obj) {
197        if (obj instanceof HotSpotSignature) {
198            HotSpotSignature other = (HotSpotSignature) obj;
199            if (other.originalString.equals(originalString)) {
200                assert other.parameters.equals(parameters);
201                assert other.returnType.equals(returnType);
202                return true;
203            }
204        }
205        return false;
206    }
207
208    @Override
209    public int hashCode() {
210        return originalString.hashCode();
211    }
212}