1 /*
2 * Copyright 2003-2007 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.codehaus.groovy.reflection;
17
18 import groovy.lang.MetaClassImpl;
19 import groovy.lang.MetaMethod;
20 import groovy.lang.MissingMethodException;
21
22 import org.codehaus.groovy.classgen.BytecodeHelper;
23 import org.codehaus.groovy.runtime.InvokerInvocationException;
24 import org.codehaus.groovy.runtime.callsite;
25 import org.codehaus.groovy.runtime.metaclass.MethodHelper;
26
27 import java.lang.ref.SoftReference;
28 import java.lang.reflect.Constructor;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
31 import java.util;
32
33 /**
34 * @author Alex.Tkachman
35 */
36 public class CachedMethod extends MetaMethod implements Comparable {
37 public final CachedClass cachedClass;
38
39 private final Method cachedMethod;
40 private int hashCode;
41
42 private static MyComparator comparator = new MyComparator();
43
44 private SoftReference<Constructor> pogoCallSiteConstructor, pojoCallSiteConstructor, staticCallSiteConstructor;
45
46 public CachedMethod(CachedClass clazz, Method method) {
47 this.cachedMethod = method;
48 this.cachedClass = clazz;
49 }
50
51 public CachedMethod(Method method) {
52 this(ReflectionCache.getCachedClass(method.getDeclaringClass()),method);
53 }
54
55 public static CachedMethod find(Method method) {
56 CachedMethod[] methods = ReflectionCache.getCachedClass(method.getDeclaringClass()).getMethods();
57 // for (int i = 0; i < methods.length; i++) {
58 // CachedMethod cachedMethod = methods[i];
59 // if (cachedMethod.cachedMethod.equals(method))
60 // return cachedMethod;
61 // }
62 // return null;
63 int i = Arrays.binarySearch(methods, method, comparator);
64 if (i < 0)
65 return null;
66
67 return methods[i];
68 }
69
70 protected Class[] getPT() {
71 return cachedMethod.getParameterTypes();
72 }
73
74 public String getName() {
75 return cachedMethod.getName();
76 }
77
78 public String getDescriptor() {
79 return BytecodeHelper.getMethodDescriptor(getReturnType(), getNativeParameterTypes());
80 }
81
82 public CachedClass getDeclaringClass() {
83 return cachedClass;
84 }
85
86 public final Object invoke(Object object, Object[] arguments) {
87 try {
88 return cachedMethod.invoke(object, arguments);
89 } catch (IllegalArgumentException e) {
90 throw new InvokerInvocationException(e);
91 } catch (IllegalAccessException e) {
92 throw new InvokerInvocationException(e);
93 } catch (InvocationTargetException e) {
94 Throwable cause = e.getCause();
95 throw (cause instanceof RuntimeException && !(cause instanceof MissingMethodException)) ?
96 (RuntimeException) cause : new InvokerInvocationException(e);
97 }
98 }
99
100 public ParameterTypes getParamTypes() {
101 return null;
102 }
103
104 public Class getReturnType() {
105 return cachedMethod.getReturnType();
106 }
107
108 public int getParamsCount() {
109 return getParameterTypes().length;
110 }
111
112 public int getModifiers() {
113 return cachedMethod.getModifiers();
114 }
115
116
117 public String getSignature() {
118 return getName() + getDescriptor();
119 }
120
121 public final Method setAccessible() {
122 // if (queuedToCompile.compareAndSet(false,true)) {
123 // if (isCompilable())
124 // CompileThread.addMethod(this);
125 // }
126 return cachedMethod;
127 }
128
129 public boolean isStatic() {
130 return MethodHelper.isStatic(cachedMethod);
131 }
132
133 public int compareTo(Object o) {
134 if (o instanceof CachedMethod)
135 return compareToCachedMethod((CachedMethod)o);
136 else
137 return compareToMethod((Method)o);
138 }
139
140 private int compareToCachedMethod(CachedMethod m) {
141 if (m == null)
142 return -1;
143
144 final int strComp = getName().compareTo(m.getName());
145 if (strComp != 0)
146 return strComp;
147
148 final int retComp = getReturnType().getName().compareTo(m.getReturnType().getName());
149 if (retComp != 0)
150 return retComp;
151
152 CachedClass[] params = getParameterTypes();
153 CachedClass [] mparams = m.getParameterTypes();
154
155 final int pd = params.length - mparams.length;
156 if (pd != 0)
157 return pd;
158
159 for (int i = 0; i != params.length; ++i)
160 {
161 final int nameComp = params[i].getName().compareTo(mparams[i].getName());
162 if (nameComp != 0)
163 return nameComp;
164 }
165
166 throw new RuntimeException("Should never happen");
167 }
168
169 private int compareToMethod(Method m) {
170 if (m == null)
171 return -1;
172
173 final int strComp = getName().compareTo(m.getName());
174 if (strComp != 0)
175 return strComp;
176
177 final int retComp = getReturnType().getName().compareTo(m.getReturnType().getName());
178 if (retComp != 0)
179 return retComp;
180
181 CachedClass[] params = getParameterTypes();
182 Class [] mparams = m.getParameterTypes();
183
184 final int pd = params.length - mparams.length;
185 if (pd != 0)
186 return pd;
187
188 for (int i = 0; i != params.length; ++i)
189 {
190 final int nameComp = params[i].getName().compareTo(mparams[i].getName());
191 if (nameComp != 0)
192 return nameComp;
193 }
194
195 return 0;
196 }
197
198 public boolean equals(Object o) {
199 return (o instanceof CachedMethod && cachedMethod.equals(((CachedMethod)o).cachedMethod))
200 || (o instanceof Method && cachedMethod.equals(o));
201 }
202
203 public int hashCode() {
204 if (hashCode == 0) {
205 hashCode = cachedMethod.hashCode();
206 if (hashCode == 0)
207 hashCode = 0xcafebebe;
208 }
209 return hashCode;
210 }
211
212 public String toString() {
213 return cachedMethod.toString();
214 }
215
216 public CallSite createPogoMetaMethodSite(CallSite site, MetaClassImpl metaClass, Class[] params) {
217 if (!hasPogoCallSiteConstructor()) {
218 Constructor constr = null;
219 if (CallSiteGenerator.isCompilable(this)) {
220 constr = CallSiteGenerator.compilePogoMethod(this);
221
222 if (constr != null)
223 pogoCallSiteConstructor = new SoftReference<Constructor> (constr);
224 }
225 }
226
227 if (hasPogoCallSiteConstructor()) {
228 final Constructor constructor = pogoCallSiteConstructor.get();
229 if (constructor != null) {
230 try {
231 return (CallSite) constructor.newInstance(site, metaClass, this, params);
232 } catch (Throwable e) { //
233 }
234 }
235 }
236
237 return new PogoMetaMethodSite.PogoCachedMethodSiteNoUnwrapNoCoerce(site, metaClass, this, params);
238 }
239
240 public CallSite createPojoMetaMethodSite(CallSite site, MetaClassImpl metaClass, Class[] params) {
241 if (!hasPojoCallSiteConstructor()) {
242 Constructor constr = null;
243 if (CallSiteGenerator.isCompilable(this)) {
244 constr = CallSiteGenerator.compilePojoMethod(this);
245
246 if (constr != null)
247 pojoCallSiteConstructor = new SoftReference<Constructor> (constr);
248 }
249 }
250
251 if (hasPogoCallSiteConstructor()) {
252 final Constructor constructor = pojoCallSiteConstructor.get();
253 if (constructor != null) {
254 try {
255 return (CallSite) constructor.newInstance(site, metaClass, this, params);
256 } catch (Throwable e) { //
257 }
258 }
259 }
260
261 return new PojoMetaMethodSite.PojoCachedMethodSiteNoUnwrapNoCoerce(site, metaClass, this, params);
262 }
263
264 public CallSite createStaticMetaMethodSite(CallSite site, MetaClassImpl metaClass, Class[] params) {
265 if (!hasStaticCallSiteConstructor()) {
266 Constructor constr = null;
267 if (CallSiteGenerator.isCompilable(this)) {
268 constr = CallSiteGenerator.compileStaticMethod(this);
269
270 if (constr != null)
271 staticCallSiteConstructor = new SoftReference<Constructor> (constr);
272 }
273 }
274
275 if (hasStaticCallSiteConstructor()) {
276 final Constructor constructor = staticCallSiteConstructor.get();
277 if (constructor != null) {
278 try {
279 return (CallSite) constructor.newInstance(site, metaClass, this, params);
280 } catch (Throwable e) { //
281 }
282 }
283 }
284
285 return new StaticMetaMethodSite.StaticMetaMethodSiteNoUnwrapNoCoerce(site, metaClass, this, params);
286 }
287
288 public boolean hasPogoCallSiteConstructor() {
289 return pogoCallSiteConstructor != null && pogoCallSiteConstructor.get() != null;
290 }
291
292 public boolean hasPojoCallSiteConstructor() {
293 return pojoCallSiteConstructor != null && pojoCallSiteConstructor.get() != null;
294 }
295
296 public boolean hasStaticCallSiteConstructor() {
297 return staticCallSiteConstructor != null && staticCallSiteConstructor.get() != null;
298 }
299
300 private static class MyComparator implements Comparator {
301 public int compare(Object o1, Object o2) {
302 if (o1 instanceof CachedMethod)
303 return ((CachedMethod)o1).compareTo(o2);
304 else if (o2 instanceof CachedMethod)
305 return -((CachedMethod)o2).compareTo(o1);
306 else
307 // really, this should never happen, it's eveidence of corruption if it does
308 throw new ClassCastException("One of the two comperables must be a CachedMethod");
309 }
310 }
311
312 public Method getCachedMethod() {
313 return cachedMethod;
314 }
315
316 // private static class CompileThread extends Thread {
317 // static final LinkedBlockingQueue queue = new LinkedBlockingQueue();
318 //
319 // static {
320 // new CompileThread().start();
321 // }
322 //
323 // private CompileThread() {
324 // setDaemon(true);
325 // setPriority(Thread.MAX_PRIORITY-2);
326 // }
327 //
328 // public void run() {
329 // try {
330 // while (true) {
331 // final CachedMethod method = (CachedMethod) queue.take();
332 // if (method != null) {
333 // CallSiteGenerator.compilePogoMethod(method);
334 // }
335 // }
336 // }
337 // catch (InterruptedException e) {//
338 // }
339 // }
340 //
341 // public static void addMethod (CachedMethod method) {
342 // try {
343 // queue.put(method);
344 // } catch (InterruptedException e) {
345 // }
346 // }
347 // }
348
349 }
350