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.runtime.callsite;
17
18 import groovy.lang.GroovyObject;
19 import groovy.lang.GroovyRuntimeException;
20 import groovy.lang.MetaClassImpl;
21 import groovy.lang.MetaMethod;
22 import org.codehaus.groovy.reflection.CachedMethod;
23 import org.codehaus.groovy.runtime.MetaClassHelper;
24 import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
25
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28
29 /**
30 * POGO call site
31 * meta class - cached
32 * method - cached
33 */
34 public class PogoMetaMethodSite extends MetaMethodSite {
35 public PogoMetaMethodSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class params[]) {
36 super(site, metaClass, metaMethod, params);
37 }
38
39 public Object invoke(Object receiver, Object[] args) throws Throwable {
40 MetaClassHelper.unwrap(args);
41 try {
42 return metaMethod.doMethodInvoke(receiver, args);
43 } catch (GroovyRuntimeException gre) {
44 throw ScriptBytecodeAdapter.unwrap(gre);
45 }
46 }
47
48 public Object callCurrent(GroovyObject receiver, Object[] args) throws Throwable {
49 if(checkCall(receiver, args)) {
50 try {
51 return invoke(receiver,args);
52 } catch (GroovyRuntimeException gre) {
53 throw ScriptBytecodeAdapter.unwrap(gre);
54 }
55 } else {
56 return CallSiteArray.defaultCallCurrent(this, receiver, args);
57 }
58 }
59
60 public Object call(Object receiver, Object[] args) throws Throwable {
61 if(checkCall(receiver, args)) {
62 try {
63 return invoke(receiver,args);
64 } catch (GroovyRuntimeException gre) {
65 throw ScriptBytecodeAdapter.unwrap(gre);
66 }
67 } else {
68 return CallSiteArray.defaultCall(this, receiver, args);
69 }
70 }
71
72 protected boolean checkCall(Object receiver, Object[] args) {
73 try {
74 return usage.get() == 0
75 && ((GroovyObject)receiver).getMetaClass() == metaClass // metaClass still be valid
76 && MetaClassHelper.sameClasses(params, args);
77 }
78 catch (NullPointerException e) {
79 if (receiver == null)
80 return false;
81 throw e;
82 }
83 catch (ClassCastException e) {
84 if (!(receiver instanceof GroovyObject))
85 return false;
86 throw e;
87 }
88 }
89
90 protected boolean checkCall(Object receiver) {
91 try {
92 return usage.get() == 0
93 && ((GroovyObject)receiver).getMetaClass() == metaClass // metaClass still be valid
94 && MetaClassHelper.sameClasses(params);
95 }
96 catch (NullPointerException e) {
97 if (receiver == null)
98 return false;
99 throw e;
100 }
101 catch (ClassCastException e) {
102 if (!(receiver instanceof GroovyObject))
103 return false;
104 throw e;
105 }
106 }
107
108 protected boolean checkCall(Object receiver, Object arg1) {
109 try {
110 return usage.get() == 0
111 && ((GroovyObject)receiver).getMetaClass() == metaClass // metaClass still be valid
112 && MetaClassHelper.sameClasses(params, arg1);
113 }
114 catch (NullPointerException e) {
115 if (receiver == null)
116 return false;
117 throw e;
118 }
119 catch (ClassCastException e) {
120 if (!(receiver instanceof GroovyObject))
121 return false;
122 throw e;
123 }
124 }
125
126 protected boolean checkCall(Object receiver, Object arg1, Object arg2) {
127 try {
128 return usage.get() == 0
129 && ((GroovyObject)receiver).getMetaClass() == metaClass // metaClass still be valid
130 && MetaClassHelper.sameClasses(params, arg1, arg2);
131 }
132 catch (NullPointerException e) {
133 if (receiver == null)
134 return false;
135 throw e;
136 }
137 catch (ClassCastException e) {
138 if (!(receiver instanceof GroovyObject))
139 return false;
140 throw e;
141 }
142 }
143
144 protected boolean checkCall(Object receiver, Object arg1, Object arg2, Object arg3) {
145 try {
146 return usage.get() == 0
147 && ((GroovyObject)receiver).getMetaClass() == metaClass // metaClass still be valid
148 && MetaClassHelper.sameClasses(params, arg1, arg2, arg3);
149 }
150 catch (NullPointerException e) {
151 if (receiver == null)
152 return false;
153 throw e;
154 }
155 catch (ClassCastException e) {
156 if (!(receiver instanceof GroovyObject))
157 return false;
158 throw e;
159 }
160 }
161
162 protected boolean checkCall(Object receiver, Object arg1, Object arg2, Object arg3, Object arg4) {
163 try {
164 return usage.get() == 0
165 && ((GroovyObject)receiver).getMetaClass() == metaClass // metaClass still be valid
166 && MetaClassHelper.sameClasses(params, arg1, arg2, arg3, arg4);
167 }
168 catch (NullPointerException e) {
169 if (receiver == null)
170 return false;
171 throw e;
172 }
173 catch (ClassCastException e) {
174 if (!(receiver instanceof GroovyObject))
175 return false;
176 throw e;
177 }
178 }
179
180 public static CallSite createPogoMetaMethodSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object[] args) {
181 if (metaMethod.getClass() == CachedMethod.class)
182 return createCachedMethodSite (site, metaClass, (CachedMethod) metaMethod, params, args);
183
184 return createNonAwareCallSite(site, metaClass, metaMethod, params, args);
185 }
186
187 private static CallSite createNonAwareCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object[] args) {
188 if (metaMethod.correctArguments(args) == args) {
189 if (noWrappers(args)) {
190 if (noCoerce(metaMethod,args))
191 return new PogoMetaMethodSiteNoUnwrap(site, metaClass, metaMethod, params);
192 else {
193 return new PogoMetaMethodSiteNoUnwrapNoCoerce(site, metaClass, metaMethod, params);
194 }
195 }
196 }
197 return new PogoMetaMethodSite(site, metaClass, metaMethod, params);
198 }
199
200 public static CallSite createCachedMethodSite(CallSite site, MetaClassImpl metaClass, CachedMethod metaMethod, Class[] params, Object[] args) {
201 if (metaMethod.correctArguments(args) == args) {
202 if (noWrappers(args)) {
203 if (noCoerce(metaMethod,args))
204 return new PogoCachedMethodSiteNoUnwrap(site, metaClass, metaMethod, params);
205 else {
206 return metaMethod.createPogoMetaMethodSite(site, metaClass, params);
207 }
208 }
209 }
210 return new PogoCachedMethodSite(site, metaClass, metaMethod, params);
211 }
212
213 public static class PogoCachedMethodSite extends PogoMetaMethodSite {
214 final Method reflect;
215
216 public PogoCachedMethodSite(CallSite site, MetaClassImpl metaClass, CachedMethod metaMethod, Class[] params) {
217 super(site, metaClass, metaMethod, params);
218 reflect = metaMethod.setAccessible();
219 }
220
221 public Object invoke(Object receiver, Object[] args) throws Throwable {
222 MetaClassHelper.unwrap(args);
223 args = metaMethod.coerceArgumentsToClasses(args);
224 try {
225 return reflect.invoke(receiver, args);
226 } catch (InvocationTargetException e) {
227 Throwable cause = e.getCause();
228 if (cause instanceof GroovyRuntimeException) {
229 throw ScriptBytecodeAdapter.unwrap ((GroovyRuntimeException) cause);
230 } else {
231 throw cause;
232 }
233 }
234 }
235 }
236
237 public static class PogoCachedMethodSiteNoUnwrap extends PogoCachedMethodSite {
238
239 public PogoCachedMethodSiteNoUnwrap(CallSite site, MetaClassImpl metaClass, CachedMethod metaMethod, Class params[]) {
240 super(site, metaClass, metaMethod, params);
241 }
242
243 public final Object invoke(Object receiver, Object[] args) throws Throwable {
244 args = metaMethod.coerceArgumentsToClasses(args);
245 try {
246 return reflect.invoke(receiver, args);
247 } catch (InvocationTargetException e) {
248 Throwable cause = e.getCause();
249 if (cause instanceof GroovyRuntimeException) {
250 throw ScriptBytecodeAdapter.unwrap ((GroovyRuntimeException) cause);
251 } else {
252 throw cause;
253 }
254 }
255 }
256 }
257
258 public static class PogoCachedMethodSiteNoUnwrapNoCoerce extends PogoCachedMethodSite {
259
260 public PogoCachedMethodSiteNoUnwrapNoCoerce(CallSite site, MetaClassImpl metaClass, CachedMethod metaMethod, Class params[]) {
261 super(site, metaClass, metaMethod, params);
262 }
263
264 public final Object invoke(Object receiver, Object[] args) throws Throwable {
265 try {
266 return reflect.invoke(receiver, args);
267 } catch (InvocationTargetException e) {
268 Throwable cause = e.getCause();
269 if (cause instanceof GroovyRuntimeException) {
270 throw ScriptBytecodeAdapter.unwrap ((GroovyRuntimeException) cause);
271 } else {
272 throw cause;
273 }
274 }
275 }
276 }
277
278 /**
279 * Call site where we know there is no need to unwrap arguments
280 */
281 public static class PogoMetaMethodSiteNoUnwrap extends PogoMetaMethodSite {
282
283 public PogoMetaMethodSiteNoUnwrap(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class params[]) {
284 super(site, metaClass, metaMethod, params);
285 }
286
287 public final Object invoke(Object receiver, Object[] args) throws Throwable {
288 try {
289 return metaMethod.doMethodInvoke(receiver, args);
290 } catch (GroovyRuntimeException gre) {
291 throw ScriptBytecodeAdapter.unwrap(gre);
292 }
293 }
294 }
295
296 /**
297 * Call site where we know there is no need neither unwrap nor coerce arguments
298 */
299 public static class PogoMetaMethodSiteNoUnwrapNoCoerce extends PogoMetaMethodSite {
300
301 public PogoMetaMethodSiteNoUnwrapNoCoerce(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class params[]) {
302 super(site, metaClass, metaMethod, params);
303 }
304
305 public final Object invoke(Object receiver, Object[] args) throws Throwable {
306 try {
307 return metaMethod.invoke(receiver, args);
308 } catch (GroovyRuntimeException gre) {
309 throw ScriptBytecodeAdapter.unwrap(gre);
310 }
311 }
312 }
313 }