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.MetaClass;
19 import groovy.lang.MetaClassImpl;
20 import groovy.lang.GroovyInterceptable;
21 import groovy.lang.GroovyObject;
22 import org.codehaus.groovy.runtime.InvokerHelper;
23 import org.codehaus.groovy.reflection.ClassInfo;
24
25 public final class CallSiteArray {
26 public final CallSite[] array;
27
28 public static final Object [] NOPARAM = new Object[0];
29 public final Class owner;
30
31 public CallSiteArray(Class owner, String [] names) {
32 this.owner = owner;
33 array = new CallSite[names.length];
34 for (int i = 0; i < array.length; i++) {
35 array[i] = new AbstractCallSite(this, i, names[i]);
36 }
37 }
38
39 public static Object defaultCall(CallSite callSite, Object receiver, Object[] args) throws Throwable {
40 return createCallSite(callSite, receiver, args).call(receiver, args);
41 }
42
43 public static Object defaultCallCurrent(CallSite callSite, GroovyObject receiver, Object[] args) throws Throwable {
44 return createCallCurrentSite(callSite, receiver, args, callSite.getArray().owner).callCurrent(receiver, args);
45 }
46
47 public static Object defaultCallStatic(CallSite callSite, Class receiver, Object[] args) throws Throwable {
48 return createCallStaticSite(callSite, receiver, args).callStatic(receiver,args);
49 }
50
51 public static Object defaultCallConstructor(CallSite callSite, Object receiver, Object[] args) throws Throwable {
52 return createCallConstructorSite(callSite, (Class) receiver, args).callConstructor(receiver, args);
53 }
54
55 private static CallSite createCallStaticSite(CallSite callSite, Class receiver, Object[] args) {
56 CallSite site;
57 MetaClass metaClass = InvokerHelper.getMetaClass(receiver);
58 if (metaClass instanceof MetaClassImpl) {
59 site = ((MetaClassImpl)metaClass).createStaticSite(callSite, args);
60 }
61 else
62 site = new StaticMetaClassSite(callSite, metaClass);
63
64 replaceCallSite(callSite, site);
65 return site;
66 }
67
68 private static CallSite createCallConstructorSite(CallSite callSite, Class receiver, Object[] args) {
69 MetaClass metaClass = InvokerHelper.getMetaClass(receiver);
70
71 CallSite site;
72 if (metaClass instanceof MetaClassImpl) {
73 site = ((MetaClassImpl)metaClass).createConstructorSite(callSite, args);
74 }
75 else
76 site = new MetaClassConstructorSite(callSite, metaClass);
77
78 replaceCallSite(callSite, site);
79 return site;
80 }
81
82 private static CallSite createCallCurrentSite(CallSite callSite, GroovyObject receiver, Object[] args, Class sender) {
83 CallSite site;
84 if (receiver instanceof GroovyInterceptable)
85 site = new PogoInterceptableSite(callSite);
86 else {
87 MetaClass metaClass = receiver.getMetaClass();
88 if (receiver.getClass() != metaClass.getTheClass() && !metaClass.getTheClass().isInterface()) {
89 site = new PogoInterceptableSite(callSite);
90 }
91 else
92 if (metaClass instanceof MetaClassImpl) {
93 site = ((MetaClassImpl)metaClass).createPogoCallCurrentSite(callSite, sender, args);
94 }
95 else
96 site = new PogoMetaClassSite(callSite, metaClass);
97 }
98
99 replaceCallSite(callSite, site);
100 return site;
101 }
102
103 // for MetaClassImpl we try to pick meta method,
104 // otherwise or if method doesn't exist we make call via POJO meta class
105 private static CallSite createPojoSite(CallSite callSite, Object receiver, Object[] args) {
106 final Class klazz = receiver.getClass();
107 MetaClass metaClass = InvokerHelper.getMetaClass(receiver);
108 if (callSite.getUsage().get() == 0 && metaClass instanceof MetaClassImpl) {
109 final MetaClassImpl mci = (MetaClassImpl) metaClass;
110 final ClassInfo info = mci.getTheCachedClass().classInfo;
111 if (info.hasPerInstanceMetaClasses()) {
112 return new PerInstancePojoMetaClassSite(callSite, info);
113 } else {
114 return mci.createPojoCallSite(callSite, receiver, args);
115 }
116 }
117
118 ClassInfo info = ClassInfo.getClassInfo(klazz);
119 if (info.hasPerInstanceMetaClasses())
120 return new PerInstancePojoMetaClassSite(callSite, info);
121 else
122 return new PojoMetaClassSite(callSite, metaClass);
123 }
124
125 private static CallSite createPogoSite(CallSite callSite, Object receiver, Object[] args) {
126 if (receiver instanceof GroovyInterceptable)
127 return new PogoInterceptableSite(callSite);
128
129 MetaClass metaClass = ((GroovyObject)receiver).getMetaClass();
130
131 if (metaClass instanceof MetaClassImpl) {
132 return ((MetaClassImpl)metaClass).createPogoCallSite(callSite, args);
133 }
134
135 return new PogoMetaClassSite(callSite, metaClass);
136 }
137
138 private static CallSite createCallSite(CallSite callSite, Object receiver, Object[] args) {
139 CallSite site;
140 if (receiver == null)
141 return new NullCallSite(callSite);
142
143 if (receiver instanceof Class)
144 site = createCallStaticSite(callSite, (Class) receiver, args);
145 else if (receiver instanceof GroovyObject) {
146 site = createPogoSite(callSite, receiver, args);
147 } else {
148 site = createPojoSite(callSite, receiver, args);
149 }
150
151 replaceCallSite(callSite, site);
152 return site;
153 }
154
155 private static void replaceCallSite(CallSite oldSite, CallSite newSite) {
156 oldSite.getArray().array [oldSite.getIndex()] = newSite;
157 }
158 }