IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
Call.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2010 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24
25using System;
26using System.Diagnostics;
27using System.Linq;
28using System.Xml.Linq;
29
30using IKVM.Reflection;
32using IKVM.Runtime;
33
34using Type = IKVM.Reflection.Type;
35
37{
38
39 [Instruction("call")]
40 internal class Call : Instruction
41 {
42
48 public static new Call Read(XElement element)
49 {
50 var inst = new Call();
51 Load(inst, element);
52 return inst;
53 }
54
60 public static void Load(Call inst, XElement element)
61 {
62 inst.Class = (string)element.Attribute("class");
63 inst.Type = (string)element.Attribute("type");
64 inst.Name = (string)element.Attribute("name");
65 inst.Sig = (string)element.Attribute("sig");
66 }
67
68 readonly OpCode opcode;
69
73 public Call() : this(OpCodes.Call)
74 {
75
76 }
77
82 protected Call(OpCode opcode)
83 {
84 this.opcode = opcode;
85 }
86
87 public string Class { get; set; }
88
89 public string Type { get; set; }
90
91 public string Name { get; set; }
92
93 public string Sig { get; set; }
94
95 internal sealed override void Generate(CodeGenContext context, CodeEmitter ilgen)
96 {
97 if (Name == null)
98 throw new MapXmlException("Missing name.");
99
100 if (Name == ".ctor")
101 {
102 Debug.Assert(Class == null && Type != null);
103
104 var argTypes = context.ClassLoader.ArgTypeListFromSig(Sig);
105 var ci = context.ClassLoader.Context.Resolver.ResolveCoreType(Type).AsReflection().GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, argTypes, null);
106 if (ci == null)
107 {
108 throw new InvalidOperationException("Missing .ctor: " + Type + "..ctor" + Sig);
109 }
110 ilgen.Emit(opcode, ci);
111 }
112 else
113 {
114 Debug.Assert(Class == null ^ Type == null);
115 if (Class != null)
116 {
117 Debug.Assert(Sig != null);
118 var method = context.ClassLoader.LoadClassByName(Class).GetMethod(Name, Sig, false);
119 if (method == null)
120 {
121 throw new InvalidOperationException("method not found: " + Class + "." + Name + Sig);
122 }
123 method.Link();
124 // TODO this code is part of what Compiler.CastInterfaceArgs (in compiler.cs) does,
125 // it would be nice if we could avoid this duplication...
126 var argTypeWrappers = method.GetParameters();
127 for (int i = 0; i < argTypeWrappers.Length; i++)
128 {
129 if (argTypeWrappers[i].IsGhost)
130 {
131 CodeEmitterLocal[] temps = new CodeEmitterLocal[argTypeWrappers.Length + (method.IsStatic ? 0 : 1)];
132 for (int j = temps.Length - 1; j >= 0; j--)
133 {
134 RuntimeJavaType tw;
135 if (method.IsStatic)
136 {
137 tw = argTypeWrappers[j];
138 }
139 else
140 {
141 if (j == 0)
142 {
143 tw = method.DeclaringType;
144 }
145 else
146 {
147 tw = argTypeWrappers[j - 1];
148 }
149 }
150 if (tw.IsGhost)
151 {
152 tw.EmitConvStackTypeToSignatureType(ilgen, null);
153 }
154 temps[j] = ilgen.DeclareLocal(tw.TypeAsSignatureType);
155 ilgen.Emit(OpCodes.Stloc, temps[j]);
156 }
157 for (int j = 0; j < temps.Length; j++)
158 {
159 ilgen.Emit(OpCodes.Ldloc, temps[j]);
160 }
161 break;
162 }
163 }
164 if (opcode.Value == OpCodes.Call.Value)
165 {
166 method.EmitCall(ilgen);
167 }
168 else if (opcode.Value == OpCodes.Callvirt.Value)
169 {
170 method.EmitCallvirt(ilgen);
171 }
172 else if (opcode.Value == OpCodes.Newobj.Value)
173 {
174 method.EmitNewobj(ilgen);
175 }
176 else
177 {
178 // ldftn or ldvirtftn
179 ilgen.Emit(opcode, (MethodInfo)method.GetMethod());
180 }
181 }
182 else
183 {
184 Type[] argTypes;
185 if (Sig.StartsWith("("))
186 {
187 argTypes = context.ClassLoader.ArgTypeListFromSig(Sig);
188 }
189 else if (Sig == "")
190 {
191 argTypes = Reflection.Type.EmptyTypes;
192 }
193 else
194 {
195 string[] types = Sig.Split(';');
196 argTypes = new Type[types.Length];
197 for (int i = 0; i < types.Length; i++)
198 {
199 argTypes[i] = context.ClassLoader.Context.Resolver.ResolveCoreType(types[i]).AsReflection();
200 }
201 }
202
203 var ti = context.ClassLoader.Context.Resolver.ResolveCoreType(Type).AsReflection();
204 if (ti == null)
205 {
206 throw new InvalidOperationException("Missing type: " + Type);
207 }
208
209 var mi = ti.GetMethod(Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, null, argTypes, null);
210 if (mi == null)
211 {
212 var ta = argTypes.Select(i => i.AssemblyQualifiedName).ToArray();
213 var m = ti.GetMethods().FirstOrDefault(i => i.Name == Name);
214 throw new InvalidOperationException("Missing method: " + ti.FullName + "." + Name + Sig + $" -> ({string.Join("; ", ta)}). {(m != null ? string.Join(";", m.GetParameters().Select(i => i.ParameterType.AssemblyQualifiedName)) : null)}");
215 }
216
217 ilgen.Emit(opcode, mi);
218 }
219 }
220 }
221
222 }
223
224}
global::java.lang.Class Class
global::java.lang.invoke.LambdaForm.Name Name
IKVM.Runtime.ClassFile.Method.Instruction Instruction
Definition compiler.cs:44