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;
19
20 import org.codehaus.groovy.reflection.CachedClass;
21 import org.codehaus.groovy.reflection.CachedField;
22 import org.codehaus.groovy.reflection.ParameterTypes;
23 import org.codehaus.groovy.runtime.ArrayUtil;
24 import org.codehaus.groovy.runtime.GroovyCategorySupport;
25 import org.codehaus.groovy.runtime.InvokerHelper;
26 import org.codehaus.groovy.runtime.wrappers.Wrapper;
27
28 import java.lang.reflect.Method;
29 import java.util.concurrent.atomic.AtomicInteger;
30
31 /**
32 * Base class for all call sites
33 *
34 * @author Alex Tkachman
35 */
36 public class AbstractCallSite implements CallSite {
37 protected final int index;
38 protected final String name;
39 protected final CallSiteArray array;
40 protected final AtomicInteger usage;
41
42 public AbstractCallSite(CallSiteArray array, int index, String name) {
43 this.name = name;
44 this.index = index;
45 this.array = array;
46 this.usage = GroovyCategorySupport.getCategoryNameUsage(name);
47 }
48
49 public AbstractCallSite(CallSite prev) {
50 this.name = prev.getName();
51 this.index = prev.getIndex();
52 this.array = prev.getArray();
53 this.usage = prev.getUsage();
54 }
55
56 public int getIndex() {
57 return index;
58 }
59
60 public CallSiteArray getArray() {
61 return array;
62 }
63
64 public String getName() {
65 return name;
66 }
67
68 public AtomicInteger getUsage() {
69 return usage;
70 }
71
72 public final Object callSafe(Object receiver, Object[] args) throws Throwable {
73 if (receiver == null)
74 return null;
75
76 return call (receiver, args);
77 }
78
79 public final Object callSafe (Object receiver) throws Throwable {
80 if (receiver == null)
81 return null;
82
83 return call(receiver);
84 }
85
86 public final Object callSafe (Object receiver, Object arg1) throws Throwable {
87 if (receiver == null)
88 return null;
89
90 return call(receiver, arg1);
91 }
92
93 public final Object callSafe (Object receiver, Object arg1, Object arg2) throws Throwable {
94 if (receiver == null)
95 return null;
96
97 return call(receiver, arg1, arg2);
98 }
99
100 public final Object callSafe (Object receiver, Object arg1, Object arg2, Object arg3) throws Throwable {
101 if (receiver == null)
102 return null;
103
104 return call(receiver, arg1, arg2, arg3);
105 }
106
107 public Object callSafe (Object receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable {
108 if (receiver == null)
109 return null;
110
111 return call(receiver, arg1, arg2, arg3, arg4);
112 }
113
114
115
116 public Object call(Object receiver, Object[] args) throws Throwable {
117 return CallSiteArray.defaultCall(this, receiver, args);
118 }
119
120 public Object call (Object receiver) throws Throwable {
121 return call(receiver, CallSiteArray.NOPARAM);
122 }
123
124 public Object call (Object receiver, Object arg1) throws Throwable {
125 return call(receiver, ArrayUtil.createArray(arg1));
126 }
127
128 public Object call (Object receiver, Object arg1, Object arg2) throws Throwable {
129 return call(receiver, ArrayUtil.createArray(arg1, arg2));
130 }
131
132 public Object call (Object receiver, Object arg1, Object arg2, Object arg3) throws Throwable {
133 return call(receiver, ArrayUtil.createArray(arg1, arg2, arg3));
134 }
135
136 public Object call (Object receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable {
137 return call(receiver, ArrayUtil.createArray(arg1, arg2, arg3, arg4));
138 }
139
140
141
142 public Object callCurrent (GroovyObject receiver, Object [] args) throws Throwable {
143 return CallSiteArray.defaultCallCurrent(this, receiver, args);
144 }
145
146 public Object callCurrent (GroovyObject receiver) throws Throwable {
147 return callCurrent(receiver, CallSiteArray.NOPARAM);
148 }
149
150 public Object callCurrent (GroovyObject receiver, Object arg1) throws Throwable {
151 return callCurrent(receiver, ArrayUtil.createArray(arg1));
152 }
153
154 public Object callCurrent (GroovyObject receiver, Object arg1, Object arg2) throws Throwable {
155 return callCurrent(receiver, ArrayUtil.createArray(arg1, arg2));
156 }
157
158 public Object callCurrent (GroovyObject receiver, Object arg1, Object arg2, Object arg3) throws Throwable {
159 return callCurrent(receiver, ArrayUtil.createArray(arg1, arg2, arg3));
160 }
161
162 public Object callCurrent (GroovyObject receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable {
163 return callCurrent(receiver, ArrayUtil.createArray(arg1, arg2, arg3, arg4));
164 }
165
166 public Object callStatic (Class receiver, Object [] args) throws Throwable {
167 return CallSiteArray.defaultCallStatic(this, receiver, args);
168 }
169
170 public Object callStatic (Class receiver) throws Throwable {
171 return callStatic(receiver, CallSiteArray.NOPARAM);
172 }
173
174 public Object callStatic (Class receiver, Object arg1) throws Throwable {
175 return callStatic(receiver, ArrayUtil.createArray(arg1));
176 }
177
178 public Object callStatic (Class receiver, Object arg1, Object arg2) throws Throwable {
179 return callStatic(receiver, ArrayUtil.createArray(arg1, arg2));
180 }
181
182 public Object callStatic (Class receiver, Object arg1, Object arg2, Object arg3) throws Throwable {
183 return callStatic(receiver, ArrayUtil.createArray(arg1, arg2, arg3));
184 }
185
186 public Object callStatic (Class receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable {
187 return callStatic(receiver, ArrayUtil.createArray(arg1, arg2, arg3, arg4));
188 }
189
190
191 public Object callConstructor (Object receiver, Object [] args) throws Throwable {
192 return CallSiteArray.defaultCallConstructor(this, receiver, args);
193 }
194
195 public Object callConstructor (Object receiver) throws Throwable {
196 return callConstructor(receiver, CallSiteArray.NOPARAM);
197 }
198
199 public Object callConstructor (Object receiver, Object arg1) throws Throwable {
200 return callConstructor(receiver, ArrayUtil.createArray(arg1));
201 }
202
203 public Object callConstructor (Object receiver, Object arg1, Object arg2) throws Throwable {
204 return callConstructor(receiver, ArrayUtil.createArray(arg1, arg2));
205 }
206
207 public Object callConstructor (Object receiver, Object arg1, Object arg2, Object arg3) throws Throwable {
208 return callConstructor(receiver, ArrayUtil.createArray(arg1, arg2, arg3));
209 }
210
211 public Object callConstructor (Object receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable {
212 return callConstructor(receiver, ArrayUtil.createArray(arg1, arg2, arg3, arg4));
213 }
214
215 static boolean noCoerce(ParameterTypes metaMethod, Object[] args) {
216 final CachedClass[] paramClasses = metaMethod.getParameterTypes();
217 if (paramClasses.length != args.length)
218 return false;
219
220 for (int i = 0; i < paramClasses.length; i++) {
221 CachedClass paramClass = paramClasses[i];
222 if (args[i] != null && !paramClass.isDirectlyAssignable(args[i]))
223 return true;
224 }
225 return false;
226 }
227
228 static boolean noWrappers(Object[] args) {
229 for (int i = 0; i != args.length; ++i)
230 if (args [i] instanceof Wrapper)
231 return false;
232 return true;
233 }
234
235
236 public Object callGetProperty (Object receiver) throws Throwable {
237 return acceptGetProperty(receiver).getProperty(receiver);
238 }
239
240 public Object callGroovyObjectGetProperty (Object receiver) throws Throwable {
241 return acceptGroovyObjectGetProperty(receiver).getProperty(receiver);
242 }
243
244 public CallSite acceptGetProperty(Object receiver) {
245 return createGetPropertySite(receiver);
246 }
247
248 public CallSite acceptGroovyObjectGetProperty(Object receiver) {
249 return createGroovyObjectGetPropertySite(receiver);
250 }
251
252 protected final CallSite createGetPropertySite(Object receiver) {
253 if (receiver==null) {
254 return new NullCallSite(this);
255 } else if (receiver instanceof GroovyObject) {
256 return createGroovyObjectGetPropertySite(receiver);
257 } else if (receiver instanceof Class) {
258 return createClassMetaClassGetPropertySite ((Class) receiver);
259 }
260 return createPojoMetaClassGetPropertySite(receiver);
261 }
262
263 protected final CallSite createGroovyObjectGetPropertySite(Object receiver) {
264 Class aClass = receiver.getClass();
265 try {
266 final Method method = aClass.getMethod("getProperty", String.class);
267 if (method != null && method.isSynthetic() && ((GroovyObject)receiver).getMetaClass() instanceof MetaClassImpl)
268 return createPogoMetaClassGetPropertySite ((GroovyObject)receiver);
269 } catch (NoSuchMethodException e) {
270 // fall threw
271 }
272 return createPogoGetPropertySite (aClass);
273 }
274
275 public Object getProperty(Object receiver) throws Throwable {
276 throw new UnsupportedOperationException();
277 }
278
279 private CallSite createPojoMetaClassGetPropertySite(Object receiver) {
280 final MetaClass metaClass = InvokerHelper.getMetaClass(receiver);
281
282 CallSite site;
283 if (metaClass.getClass() != MetaClassImpl.class || GroovyCategorySupport.hasCategoryInCurrentThread()) {
284 site = new PojoMetaClassGetPropertySite(this);
285 }
286 else {
287 final MetaProperty effective = ((MetaClassImpl) metaClass).getEffectiveGetMetaProperty(receiver.getClass(), receiver, name, false);
288 if (effective != null) {
289 if (effective instanceof CachedField)
290 site = new GetEffectivePojoFieldSite(this, (MetaClassImpl) metaClass, (CachedField) effective);
291 else
292 site = new GetEffectivePojoPropertySite(this, (MetaClassImpl) metaClass, effective);
293 }
294 else {
295 site = new PojoMetaClassGetPropertySite(this);
296 }
297 }
298
299 array.array[index] = site;
300 return site;
301 }
302
303 private CallSite createClassMetaClassGetPropertySite(Class aClass) {
304 CallSite site = new ClassMetaClassGetPropertySite(this, aClass);
305 array.array[index] = site;
306 return site;
307 }
308
309 private CallSite createPogoMetaClassGetPropertySite(GroovyObject receiver) {
310 MetaClass metaClass = receiver.getMetaClass();
311
312 CallSite site;
313 if (metaClass.getClass() != MetaClassImpl.class || GroovyCategorySupport.hasCategoryInCurrentThread()) {
314 site = new PogoMetaClassGetPropertySite(this, metaClass);
315 }
316 else {
317 final MetaProperty effective = ((MetaClassImpl) metaClass).getEffectiveGetMetaProperty(metaClass.getClass(), receiver, name, false);
318 if (effective != null) {
319 if (effective instanceof CachedField)
320 site = new GetEffectivePogoFieldSite(this, metaClass, (CachedField) effective);
321 else
322 site = new GetEffectivePogoPropertySite(this, metaClass, effective);
323 }
324 else {
325 site = new PogoMetaClassGetPropertySite(this, metaClass);
326 }
327 }
328
329 array.array[index] = site;
330 return site;
331 }
332
333 private CallSite createPogoGetPropertySite(Class aClass) {
334 CallSite site = new PogoGetPropertySite(this, aClass);
335 array.array[index] = site;
336 return site;
337 }
338
339 public final Object callGetPropertySafe (Object receiver) throws Throwable {
340 if (receiver == null)
341 return null;
342 else
343 return callGetProperty(receiver);
344 }
345
346 public final Object callGroovyObjectGetPropertySafe (Object receiver) throws Throwable {
347 if (receiver == null)
348 return null;
349 else
350 return callGroovyObjectGetProperty(receiver);
351 }
352
353 }
354