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