IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
ReflectionFactory.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2007-2014 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*/
24using System;
25using System.Reflection;
26#if !NO_REF_EMIT
27using System.Reflection.Emit;
29
30#endif
31using System.Runtime.Serialization;
32using System.Security;
33
34using IKVM.Runtime;
37
39{
40
41 static class ReflectionFactory
42 {
43
44#if FIRST_PASS == false
45
46 static SystemAccessor systemAccessor;
47
48 static SystemAccessor SystemAccessor => JVM.Internal.BaseAccessors.Get(ref systemAccessor);
49
50#endif
51
52#if !FIRST_PASS
53
54 static object ConvertPrimitive(RuntimeJavaType tw, object value)
55 {
56 if (tw == tw.Context.PrimitiveJavaTypeFactory.BOOLEAN)
57 {
58 if (value is global::java.lang.Boolean boolean)
59 return boolean.booleanValue();
60 }
61 else if (tw == tw.Context.PrimitiveJavaTypeFactory.BYTE)
62 {
63 if (value is global::java.lang.Byte @byte)
64 return @byte.byteValue();
65 }
66 else if (tw == tw.Context.PrimitiveJavaTypeFactory.CHAR)
67 {
68 if (value is global::java.lang.Character character)
69 return character.charValue();
70 }
71 else if (tw == tw.Context.PrimitiveJavaTypeFactory.SHORT)
72 {
73 if (value is global::java.lang.Short || value is global::java.lang.Byte)
74 {
75 return ((global::java.lang.Number)value).shortValue();
76 }
77 }
78 else if (tw == tw.Context.PrimitiveJavaTypeFactory.INT)
79 {
80 if (value is global::java.lang.Integer || value is global::java.lang.Short || value is global::java.lang.Byte)
81 {
82 return ((global::java.lang.Number)value).intValue();
83 }
84 else if (value is global::java.lang.Character)
85 {
86 return (int)((global::java.lang.Character)value).charValue();
87 }
88 }
89 else if (tw == tw.Context.PrimitiveJavaTypeFactory.LONG)
90 {
91 if (value is global::java.lang.Long || value is global::java.lang.Integer || value is global::java.lang.Short || value is global::java.lang.Byte)
92 {
93 return ((global::java.lang.Number)value).longValue();
94 }
95 else if (value is global::java.lang.Character)
96 {
97 return (long)((global::java.lang.Character)value).charValue();
98 }
99 }
100 else if (tw == tw.Context.PrimitiveJavaTypeFactory.FLOAT)
101 {
102 if (value is global::java.lang.Float || value is global::java.lang.Long || value is global::java.lang.Integer || value is global::java.lang.Short || value is global::java.lang.Byte)
103 {
104 return ((global::java.lang.Number)value).floatValue();
105 }
106 else if (value is global::java.lang.Character)
107 {
108 return (float)((global::java.lang.Character)value).charValue();
109 }
110 }
111 else if (tw == tw.Context.PrimitiveJavaTypeFactory.DOUBLE)
112 {
113 if (value is global::java.lang.Double || value is global::java.lang.Float || value is global::java.lang.Long || value is global::java.lang.Integer || value is global::java.lang.Short || value is global::java.lang.Byte)
114 {
115 return ((global::java.lang.Number)value).doubleValue();
116 }
117 else if (value is global::java.lang.Character)
118 {
119 return (double)((global::java.lang.Character)value).charValue();
120 }
121 }
122 throw new global::java.lang.IllegalArgumentException();
123 }
124
125 static object[] ConvertArgs(RuntimeClassLoader loader, RuntimeJavaType[] argumentTypes, object[] args)
126 {
127 var nargs = new object[args == null ? 0 : args.Length];
128 if (nargs.Length != argumentTypes.Length)
129 throw new global::java.lang.IllegalArgumentException("wrong number of arguments");
130
131 for (int i = 0; i < nargs.Length; i++)
132 {
133 if (argumentTypes[i].IsPrimitive)
134 {
135 nargs[i] = ConvertPrimitive(argumentTypes[i], args[i]);
136 }
137 else
138 {
139 if (args[i] != null && !argumentTypes[i].EnsureLoadable(loader).IsInstance(args[i]))
140 throw new global::java.lang.IllegalArgumentException();
141
142 nargs[i] = argumentTypes[i].GhostWrap(args[i]);
143 }
144 }
145
146 return nargs;
147 }
148
149 sealed class MethodAccessorImpl : global::sun.reflect.MethodAccessor
150 {
151
152 readonly RuntimeJavaMethod mw;
153
158 internal MethodAccessorImpl(RuntimeJavaMethod mw)
159 {
160 this.mw = mw ?? throw new ArgumentNullException(nameof(mw));
161 mw.Link();
162 mw.ResolveMethod();
163 }
164
165 [IKVM.Attributes.HideFromJava]
166 public object invoke(object obj, object[] args, global::ikvm.@internal.CallerID callerID)
167 {
168 try
169 {
170 if (!mw.IsStatic && !mw.DeclaringType.IsInstance(obj))
171 {
172 if (obj == null)
173 throw new global::java.lang.NullPointerException();
174
175 throw new global::java.lang.IllegalArgumentException("object is not an instance of declaring class");
176 }
177
178 try
179 {
180 args = ConvertArgs(mw.DeclaringType.ClassLoader, mw.GetParameters(), args);
181 }
182 catch (InvalidCastException e)
183 {
184 throw new global::java.lang.IllegalArgumentException(e);
185 }
186 catch (NullReferenceException e)
187 {
188 throw new global::java.lang.IllegalArgumentException(e);
189 }
190
191 // if the method is an interface method, we must explicitly run <clinit>,
192 // because .NET reflection doesn't
193 if (mw.DeclaringType.IsInterface)
194 mw.DeclaringType.RunClassInit();
195
196 if (mw.HasCallerID)
197 args = ArrayUtil.Concat(args, callerID);
198
199 object retval;
200 try
201 {
202 retval = mw.Invoke(obj, args);
203 }
204 catch (Exception e)
205 {
206 throw new global::java.lang.reflect.InvocationTargetException(global::ikvm.runtime.Util.mapException(e));
207 }
208
209 if (mw.ReturnType.IsPrimitive && mw.ReturnType != mw.DeclaringType.Context.PrimitiveJavaTypeFactory.VOID)
210 retval = JVM.Box(retval);
211 else
212 retval = mw.ReturnType.GhostUnwrap(retval);
213
214 return retval;
215 }
216 catch (NullReferenceException e)
217 {
218 Console.Error.WriteLine("got nre " + e);
219 throw;
220 }
221 catch (global::java.lang.NullPointerException e)
222 {
223 Console.Error.WriteLine("got npe " + e);
224 throw;
225 }
226 }
227 }
228
229 sealed class ConstructorAccessorImpl : global::sun.reflect.ConstructorAccessor
230 {
231
232 readonly RuntimeJavaMethod mw;
233
238 internal ConstructorAccessorImpl(RuntimeJavaMethod mw)
239 {
240 this.mw = mw;
241 mw.Link();
242 mw.ResolveMethod();
243 }
244
245 [IKVM.Attributes.HideFromJava]
246 public object newInstance(object[] args)
247 {
248 args = ConvertArgs(mw.DeclaringType.ClassLoader, mw.GetParameters(), args);
249 try
250 {
251 return mw.CreateInstance(args);
252 }
253 catch (Exception x)
254 {
255 throw new global::java.lang.reflect.InvocationTargetException(global::ikvm.runtime.Util.mapException(x));
256 }
257 }
258 }
259
260 sealed class SerializationConstructorAccessorImpl : global::sun.reflect.ConstructorAccessor
261 {
262
263 readonly RuntimeJavaMethod mw;
264 readonly Type type;
265
271 internal SerializationConstructorAccessorImpl(global::java.lang.reflect.Constructor constructorToCall, global::java.lang.Class classToInstantiate)
272 {
273 this.type = RuntimeJavaType.FromClass(classToInstantiate).TypeAsBaseType;
274 var mw = RuntimeJavaMethod.FromExecutable(constructorToCall);
275 if (mw.DeclaringType != JVM.Context.JavaBase.TypeOfJavaLangObject)
276 {
277 this.mw = mw;
278 mw.Link();
279 mw.ResolveMethod();
280 }
281 }
282
283 [IKVM.Attributes.HideFromJava]
284 [SecuritySafeCritical]
285 public object newInstance(object[] args)
286 {
287#if NETFRAMEWORK
288 var obj = FormatterServices.GetUninitializedObject(type);
289#else
290 var obj = RuntimeHelpers.GetUninitializedObject(type);
291#endif
292 if (mw != null)
293 mw.Invoke(obj, ConvertArgs(mw.DeclaringType.ClassLoader, mw.GetParameters(), args));
294
295 return obj;
296 }
297
298 }
299
300#if !NO_REF_EMIT
301
302 sealed class BoxUtil
303 {
304
305 static readonly MethodInfo valueOfByte = typeof(global::java.lang.Byte).GetMethod("valueOf", new Type[] { typeof(byte) });
306 static readonly MethodInfo valueOfBoolean = typeof(global::java.lang.Boolean).GetMethod("valueOf", new Type[] { typeof(bool) });
307 static readonly MethodInfo valueOfChar = typeof(global::java.lang.Character).GetMethod("valueOf", new Type[] { typeof(char) });
308 static readonly MethodInfo valueOfShort = typeof(global::java.lang.Short).GetMethod("valueOf", new Type[] { typeof(short) });
309 static readonly MethodInfo valueOfInt = typeof(global::java.lang.Integer).GetMethod("valueOf", new Type[] { typeof(int) });
310 static readonly MethodInfo valueOfFloat = typeof(global::java.lang.Float).GetMethod("valueOf", new Type[] { typeof(float) });
311 static readonly MethodInfo valueOfLong = typeof(global::java.lang.Long).GetMethod("valueOf", new Type[] { typeof(long) });
312 static readonly MethodInfo valueOfDouble = typeof(global::java.lang.Double).GetMethod("valueOf", new Type[] { typeof(double) });
313 static readonly MethodInfo byteValue = typeof(global::java.lang.Byte).GetMethod("byteValue", Type.EmptyTypes);
314 static readonly MethodInfo booleanValue = typeof(global::java.lang.Boolean).GetMethod("booleanValue", Type.EmptyTypes);
315 static readonly MethodInfo charValue = typeof(global::java.lang.Character).GetMethod("charValue", Type.EmptyTypes);
316 static readonly MethodInfo shortValue = typeof(global::java.lang.Short).GetMethod("shortValue", Type.EmptyTypes);
317 static readonly MethodInfo intValue = typeof(global::java.lang.Integer).GetMethod("intValue", Type.EmptyTypes);
318 static readonly MethodInfo floatValue = typeof(global::java.lang.Float).GetMethod("floatValue", Type.EmptyTypes);
319 static readonly MethodInfo longValue = typeof(global::java.lang.Long).GetMethod("longValue", Type.EmptyTypes);
320 static readonly MethodInfo doubleValue = typeof(global::java.lang.Double).GetMethod("doubleValue", Type.EmptyTypes);
321
322 internal static void EmitUnboxArg(CodeEmitter ilgen, RuntimeJavaType type)
323 {
324 if (type == ilgen.Context.PrimitiveJavaTypeFactory.BYTE)
325 {
326 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Byte));
327 ilgen.Emit(OpCodes.Call, byteValue);
328 }
329 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.BOOLEAN)
330 {
331 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Boolean));
332 ilgen.Emit(OpCodes.Call, booleanValue);
333 }
334 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.CHAR)
335 {
336 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Character));
337 ilgen.Emit(OpCodes.Call, charValue);
338 }
339 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.SHORT
340 || type == ilgen.Context.PrimitiveJavaTypeFactory.INT
341 || type == ilgen.Context.PrimitiveJavaTypeFactory.FLOAT
342 || type == ilgen.Context.PrimitiveJavaTypeFactory.LONG
343 || type == ilgen.Context.PrimitiveJavaTypeFactory.DOUBLE)
344 {
345 ilgen.Emit(OpCodes.Dup);
346 ilgen.Emit(OpCodes.Isinst, typeof(global::java.lang.Byte));
347 CodeEmitterLabel next = ilgen.DefineLabel();
348 ilgen.EmitBrfalse(next);
349 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Byte));
350 ilgen.Emit(OpCodes.Call, byteValue);
351 ilgen.Emit(OpCodes.Conv_I1);
352 Expand(ilgen, type);
353 CodeEmitterLabel done = ilgen.DefineLabel();
354 ilgen.EmitBr(done);
355 ilgen.MarkLabel(next);
356 if (type == ilgen.Context.PrimitiveJavaTypeFactory.SHORT)
357 {
358 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Short));
359 ilgen.Emit(OpCodes.Call, shortValue);
360 }
361 else
362 {
363 ilgen.Emit(OpCodes.Dup);
364 ilgen.Emit(OpCodes.Isinst, typeof(global::java.lang.Short));
365 next = ilgen.DefineLabel();
366 ilgen.EmitBrfalse(next);
367 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Short));
368 ilgen.Emit(OpCodes.Call, shortValue);
369 Expand(ilgen, type);
370 ilgen.EmitBr(done);
371 ilgen.MarkLabel(next);
372 ilgen.Emit(OpCodes.Dup);
373 ilgen.Emit(OpCodes.Isinst, typeof(global::java.lang.Character));
374 next = ilgen.DefineLabel();
375 ilgen.EmitBrfalse(next);
376 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Character));
377 ilgen.Emit(OpCodes.Call, charValue);
378 Expand(ilgen, type);
379 ilgen.EmitBr(done);
380 ilgen.MarkLabel(next);
381 if (type == ilgen.Context.PrimitiveJavaTypeFactory.INT)
382 {
383 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Integer));
384 ilgen.Emit(OpCodes.Call, intValue);
385 }
386 else
387 {
388 ilgen.Emit(OpCodes.Dup);
389 ilgen.Emit(OpCodes.Isinst, typeof(global::java.lang.Integer));
390 next = ilgen.DefineLabel();
391 ilgen.EmitBrfalse(next);
392 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Integer));
393 ilgen.Emit(OpCodes.Call, intValue);
394 Expand(ilgen, type);
395 ilgen.EmitBr(done);
396 ilgen.MarkLabel(next);
397 if (type == ilgen.Context.PrimitiveJavaTypeFactory.LONG)
398 {
399 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Long));
400 ilgen.Emit(OpCodes.Call, longValue);
401 }
402 else
403 {
404 ilgen.Emit(OpCodes.Dup);
405 ilgen.Emit(OpCodes.Isinst, typeof(global::java.lang.Long));
406 next = ilgen.DefineLabel();
407 ilgen.EmitBrfalse(next);
408 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Long));
409 ilgen.Emit(OpCodes.Call, longValue);
410 Expand(ilgen, type);
411 ilgen.EmitBr(done);
412 ilgen.MarkLabel(next);
413 if (type == ilgen.Context.PrimitiveJavaTypeFactory.FLOAT)
414 {
415 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Float));
416 ilgen.Emit(OpCodes.Call, floatValue);
417 }
418 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.DOUBLE)
419 {
420 ilgen.Emit(OpCodes.Dup);
421 ilgen.Emit(OpCodes.Isinst, typeof(global::java.lang.Float));
422 next = ilgen.DefineLabel();
423 ilgen.EmitBrfalse(next);
424 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Float));
425 ilgen.Emit(OpCodes.Call, floatValue);
426 ilgen.EmitBr(done);
427 ilgen.MarkLabel(next);
428 ilgen.Emit(OpCodes.Castclass, typeof(global::java.lang.Double));
429 ilgen.Emit(OpCodes.Call, doubleValue);
430 }
431 else
432 {
433 throw new InvalidOperationException();
434 }
435 }
436 }
437 }
438 ilgen.MarkLabel(done);
439 }
440 else
441 {
442 type.EmitCheckcast(ilgen);
443 }
444 }
445
446 internal static void BoxReturnValue(CodeEmitter ilgen, RuntimeJavaType type)
447 {
448 if (type == ilgen.Context.PrimitiveJavaTypeFactory.VOID)
449 {
450 ilgen.Emit(OpCodes.Ldnull);
451 }
452 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.BYTE)
453 {
454 ilgen.Emit(OpCodes.Call, valueOfByte);
455 }
456 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.BOOLEAN)
457 {
458 ilgen.Emit(OpCodes.Call, valueOfBoolean);
459 }
460 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.CHAR)
461 {
462 ilgen.Emit(OpCodes.Call, valueOfChar);
463 }
464 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.SHORT)
465 {
466 ilgen.Emit(OpCodes.Call, valueOfShort);
467 }
468 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.INT)
469 {
470 ilgen.Emit(OpCodes.Call, valueOfInt);
471 }
472 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.FLOAT)
473 {
474 ilgen.Emit(OpCodes.Call, valueOfFloat);
475 }
476 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.LONG)
477 {
478 ilgen.Emit(OpCodes.Call, valueOfLong);
479 }
480 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.DOUBLE)
481 {
482 ilgen.Emit(OpCodes.Call, valueOfDouble);
483 }
484 }
485
486 static void Expand(CodeEmitter ilgen, RuntimeJavaType type)
487 {
488 if (type == ilgen.Context.PrimitiveJavaTypeFactory.FLOAT)
489 {
490 ilgen.Emit(OpCodes.Conv_R4);
491 }
492 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.LONG)
493 {
494 ilgen.Emit(OpCodes.Conv_I8);
495 }
496 else if (type == ilgen.Context.PrimitiveJavaTypeFactory.DOUBLE)
497 {
498 ilgen.Emit(OpCodes.Conv_R8);
499 }
500 }
501 }
502
506 sealed class FastMethodAccessorImpl : global::sun.reflect.MethodAccessor
507 {
508
509 internal static readonly ConstructorInfo nullPointerExceptionCtor;
510 internal static readonly ConstructorInfo nullPointerExceptionWithMessageCtor;
511 internal static readonly ConstructorInfo illegalArgumentExceptionCtor;
512 internal static readonly ConstructorInfo illegalArgumentExceptionWithMessageCtor;
513 internal static readonly ConstructorInfo illegalArgumentExceptionWithMessageAndCauseCtor;
514 internal static readonly ConstructorInfo illegalArgumentExceptionWithCauseCtor;
515 internal static readonly ConstructorInfo invocationTargetExceptionWithCauseCtor;
516
517 delegate object Invoker(object obj, object[] args, global::ikvm.@internal.CallerID callerID);
518 Invoker invoker;
519
523 static FastMethodAccessorImpl()
524 {
525 nullPointerExceptionCtor = typeof(global::java.lang.NullPointerException).GetConstructor(Type.EmptyTypes);
526 nullPointerExceptionWithMessageCtor = typeof(global::java.lang.NullPointerException).GetConstructor(new[] { typeof(string) });
527 illegalArgumentExceptionCtor = typeof(global::java.lang.IllegalArgumentException).GetConstructor(Type.EmptyTypes);
528 illegalArgumentExceptionWithMessageCtor = typeof(global::java.lang.IllegalArgumentException).GetConstructor(new[] { typeof(string) });
529 illegalArgumentExceptionWithMessageAndCauseCtor = typeof(global::java.lang.IllegalArgumentException).GetConstructor(new[] { typeof(string), typeof(Exception) });
530 illegalArgumentExceptionWithCauseCtor = typeof(global::java.lang.IllegalArgumentException).GetConstructor(new[] { typeof(Exception) });
531 invocationTargetExceptionWithCauseCtor = typeof(global::java.lang.reflect.InvocationTargetException).GetConstructor(new[] { typeof(Exception) });
532 }
533
534 sealed class RunClassInit
535 {
536
537 readonly FastMethodAccessorImpl outer;
538 readonly RuntimeJavaType tw;
539 readonly Invoker invoker;
540
547 internal RunClassInit(FastMethodAccessorImpl outer, RuntimeJavaType tw, Invoker invoker)
548 {
549 this.outer = outer;
550 this.tw = tw;
551 this.invoker = invoker;
552 }
553
554 [IKVM.Attributes.HideFromJava]
555 internal object invoke(object obj, object[] args, global::ikvm.@internal.CallerID callerID)
556 {
557 // FXBUG pre-SP1 a DynamicMethod that calls a static method doesn't trigger the cctor, so we do that explicitly.
558 // even on .NET 2.0 SP2, interface method invocations don't run the interface cctor
559 // NOTE when testing, please test both the x86 and x64 CLR JIT, because they have different bugs (even on .NET 2.0 SP2)
560 tw.RunClassInit();
561 outer.invoker = invoker;
562 return invoker(obj, args, callerID);
563 }
564
565 }
566
571 internal unsafe FastMethodAccessorImpl(RuntimeJavaMethod mw)
572 {
573 try
574 {
575 mw.DeclaringType.Finish();
576 var parameters = mw.GetParameters();
577
578 for (int i = 0; i < parameters.Length; i++)
579 {
580 parameters[i] = parameters[i].EnsureLoadable(mw.DeclaringType.ClassLoader);
581 parameters[i].Finish();
582 }
583
584 // resolve the runtime method info
585 mw.ResolveMethod();
586
587 // generate new dynamic method
588 var np = !mw.IsPublic || !mw.DeclaringType.IsPublic;
589 var dm = DynamicMethodUtil.Create($"__<FastMethodAccessor>__{mw.DeclaringType.Name.Replace(".", "_")}__{mw.Name}", mw.DeclaringType.TypeAsBaseType, np, typeof(object), new[] { typeof(object), typeof(object[]), typeof(global::ikvm.@internal.CallerID) });
590 var il = JVM.Context.CodeEmitterFactory.Create(dm);
591
592 // labels
593 var postLabel = il.DefineLabel();
594
595 // arguments passed to the method
596 var s = default(CodeEmitterLocal);
597 var n = 0;
598 var p = new CodeEmitterLocal[parameters.Length];
599
600 // load instance if not static
601 if (mw.IsStatic == false)
602 {
603 // declare variable to hold this instance
604 s = il.AllocTempLocal(mw.DeclaringType.TypeAsSignatureType);
605
606 // explicit null check for target
607 var endIsNullLabel = il.DefineLabel();
608 il.Emit(OpCodes.Ldarg_0);
609 il.Emit(OpCodes.Ldnull);
610 il.EmitBne_Un(endIsNullLabel);
611 il.Emit(OpCodes.Ldstr, "object is not an instance of declaring class");
612 il.Emit(OpCodes.Newobj, nullPointerExceptionWithMessageCtor);
613 il.Emit(OpCodes.Throw);
614 il.MarkLabel(endIsNullLabel);
615
616 // temporary variables
617 var e = il.AllocTempLocal(typeof(Exception));
618
619 // cast target to appropriate type
620 var endConvSelf = il.DefineLabel();
621 il.BeginExceptionBlock();
622 il.Emit(OpCodes.Ldarg_0);
623 mw.DeclaringType.EmitCheckcast(il);
624 mw.DeclaringType.EmitConvStackTypeToSignatureType(il, null);
625 il.Emit(OpCodes.Stloc, s);
626 il.EmitLeave(endConvSelf);
627
628 // catch InvalidCastException, store, add message, and wrap with IllegalArgumentException
629 il.BeginCatchBlock(typeof(InvalidCastException));
630 il.Emit(OpCodes.Stloc, e);
631 il.Emit(OpCodes.Ldstr, "object is not an instance of declaring class");
632 il.Emit(OpCodes.Ldloc, e);
633 il.Emit(OpCodes.Newobj, illegalArgumentExceptionWithMessageAndCauseCtor);
634 il.Emit(OpCodes.Throw);
635
636 // catch Exception, wrap with IllegalArgumentException
637 il.BeginCatchBlock(typeof(Exception));
638 il.Emit(OpCodes.Newobj, illegalArgumentExceptionWithCauseCtor);
639 il.Emit(OpCodes.Throw);
640
641 // end of convert self block
642 il.EndExceptionBlock();
643 il.MarkLabel(endConvSelf);
644 il.ReleaseTempLocal(e);
645 }
646
647 // where we start converting arguemnts
648 var convArgsLabel = il.DefineLabel();
649
650 // zero length array may be null
651 if (parameters.Length == 0)
652 {
653 il.Emit(OpCodes.Ldarg_1);
654 il.EmitBrfalse(convArgsLabel);
655 }
656
657 // check that arguments array is not null
658 var chckArgsLabel = il.DefineLabel();
659 il.Emit(OpCodes.Ldarg_1);
660 il.Emit(OpCodes.Ldnull);
661 il.EmitBne_Un(chckArgsLabel);
662 il.Emit(OpCodes.Ldstr, "wrong number of arguments");
663 il.Emit(OpCodes.Newobj, illegalArgumentExceptionWithMessageCtor);
664 il.Emit(OpCodes.Throw);
665
666 // parameters length must match number of parameters on array
667 il.MarkLabel(chckArgsLabel);
668 il.Emit(OpCodes.Ldarg_1);
669 il.Emit(OpCodes.Ldlen);
670 il.EmitLdc_I4(parameters.Length);
671 il.EmitBeq(convArgsLabel);
672 il.Emit(OpCodes.Ldstr, "wrong number of arguments");
673 il.Emit(OpCodes.Newobj, illegalArgumentExceptionWithMessageCtor);
674 il.Emit(OpCodes.Throw);
675
676 // begin parameter conversion
677 il.MarkLabel(convArgsLabel);
678
679 // emit conversion code for the remainder of the arguments
680 for (var i = 0; i < parameters.Length; i++)
681 {
682 var tw = parameters[i];
683
684 // declare variable to hold argument
685 var o = p[n++] = il.AllocTempLocal(tw.TypeAsSignatureType);
686
687 // temporary variable for exceptions
688 var e = il.AllocTempLocal(typeof(Exception));
689
690 // load and convert argument
691 var endConvArgn = il.DefineLabel();
692 il.BeginExceptionBlock();
693 il.Emit(OpCodes.Ldarg_1);
694 il.EmitLdc_I4(i);
695 il.Emit(OpCodes.Ldelem_Ref);
696 BoxUtil.EmitUnboxArg(il, tw);
697 tw.EmitConvStackTypeToSignatureType(il, null);
698 il.Emit(OpCodes.Stloc, o);
699 il.EmitLeave(endConvArgn);
700
701 // catch InvalidCastException, store, add message, and wrap with IllegalArgumentException
702 il.BeginCatchBlock(typeof(InvalidCastException));
703 il.Emit(OpCodes.Stloc, e);
704 il.Emit(OpCodes.Ldstr, $"argument type mismatch on parameter {i}");
705 il.Emit(OpCodes.Ldloc, e);
706 il.Emit(OpCodes.Newobj, illegalArgumentExceptionWithMessageAndCauseCtor);
707 il.Emit(OpCodes.Throw);
708
709 // catch Exception, wrap with IllegalArgumentException
710 il.BeginCatchBlock(typeof(Exception));
711 il.Emit(OpCodes.Stloc, e);
712 il.Emit(OpCodes.Ldstr, $"exception on parameter {i}");
713 il.Emit(OpCodes.Ldloc, e);
714 il.Emit(OpCodes.Newobj, illegalArgumentExceptionWithMessageAndCauseCtor);
715 il.Emit(OpCodes.Throw);
716
717 // end convert
718 il.EndExceptionBlock();
719 il.MarkLabel(endConvArgn);
720 il.ReleaseTempLocal(e);
721 }
722
723 // storage for return value
724 var rt = il.AllocTempLocal(typeof(object));
725
726 // call method and convert result
727 il.BeginExceptionBlock();
728
729 // this instance
730 if (s != null)
731 {
732 // reference for valuetype/ghost
733 if (mw.DeclaringType.IsNonPrimitiveValueType || mw.DeclaringType.IsGhost)
734 il.Emit(OpCodes.Ldloca, s);
735 else
736 il.Emit(OpCodes.Ldloc, s);
737
738 // finished with s
739 il.ReleaseTempLocal(s);
740 }
741
742 // load converted arguments
743 for (int i = 0; i < n; i++)
744 {
745 il.Emit(OpCodes.Ldloc, p[i]);
746 il.ReleaseTempLocal(p[i]);
747 }
748
749 // method requires caller ID passed as final argument
750 if (mw.HasCallerID)
751 il.Emit(OpCodes.Ldarg_2);
752
753 // static Java method is always a call
754 if (s == null)
755 mw.EmitCall(il);
756 else
757 mw.EmitCallvirtReflect(il); // reflection virt may be static (remapped) or non-static
758
759 // handle return value
760 mw.ReturnType.EmitConvSignatureTypeToStackType(il);
761 BoxUtil.BoxReturnValue(il, mw.ReturnType);
762 il.Emit(OpCodes.Stloc, rt);
763 il.EmitLeave(postLabel);
764
765 // catch exception from call and wrap
766 il.BeginCatchBlock(typeof(Exception));
767 il.Emit(OpCodes.Ldc_I4_0);
768 il.Emit(OpCodes.Call, il.Context.ByteCodeHelperMethods.MapException.MakeGenericMethod(il.Context.Types.Exception));
769 il.Emit(OpCodes.Newobj, invocationTargetExceptionWithCauseCtor);
770 il.Emit(OpCodes.Throw);
771 il.EndExceptionBlock();
772
773 // return from method with last return value
774 il.MarkLabel(postLabel);
775 il.Emit(OpCodes.Ldloc, rt);
776 il.ReleaseTempLocal(rt);
777 il.Emit(OpCodes.Ret);
778 il.DoEmit();
779
780 // generate invoker
781 invoker = (Invoker)dm.CreateDelegate(typeof(Invoker));
782
783 // invoker needs to run clinit, wrap in an invoker that does so
784 if ((mw.IsStatic || mw.DeclaringType.IsInterface) && mw.DeclaringType.HasStaticInitializer)
785 invoker = new Invoker(new RunClassInit(this, mw.DeclaringType, invoker).invoke);
786 }
788 {
789 throw x.ToJava();
790 }
791 }
792
793 [IKVM.Attributes.HideFromJava]
794 public object invoke(object obj, object[] args, global::ikvm.@internal.CallerID callerID)
795 {
796 try
797 {
798 return invoker(obj, args, callerID);
799 }
800 catch (MethodAccessException x)
801 {
802 // this can happen if we're calling a non-public method and the call stack doesn't have ReflectionPermission.MemberAccess
803 throw new global::java.lang.IllegalAccessException().initCause(x);
804 }
805 catch (NullReferenceException e)
806 {
807 global::java.lang.System.err.println("got NRE " + e);
808 throw;
809 }
810 }
811
812 }
813
814 sealed class FastConstructorAccessorImpl : global::sun.reflect.ConstructorAccessor
815 {
816
817 delegate object Invoker(object[] args);
818 Invoker invoker;
819
820 internal FastConstructorAccessorImpl(global::java.lang.reflect.Constructor constructor)
821 {
822 try
823 {
824 var mw = RuntimeJavaMethod.FromExecutable(constructor);
825
826 mw.DeclaringType.Finish();
827 var parameters = mw.GetParameters();
828
829 for (int i = 0; i < parameters.Length; i++)
830 {
831 parameters[i] = parameters[i].EnsureLoadable(mw.DeclaringType.ClassLoader);
832 parameters[i].Finish();
833 }
834
835 // resolve the runtime method info
836 mw.ResolveMethod();
837 var np = !mw.IsPublic || !mw.DeclaringType.IsPublic;
838 var dm = DynamicMethodUtil.Create($"__<FastConstructorAccessor>__{mw.DeclaringType.Name.Replace(".", "_")}__{mw.Name}", mw.DeclaringType.TypeAsTBD, np, typeof(object), new[] { typeof(object[]) });
839 var il = JVM.Context.CodeEmitterFactory.Create(dm);
840
841 // labels
842 var postLabel = il.DefineLabel();
843
844 // local variables for arguments passed to constructor
845 var n = 0;
846 var p = new CodeEmitterLocal[parameters.Length];
847
848 // where we start converting arguemnts
849 var convArgsLabel = il.DefineLabel();
850
851 // zero length array may be null
852 if (parameters.Length == 0)
853 {
854 il.Emit(OpCodes.Ldarg_0);
855 il.EmitBrfalse(convArgsLabel);
856 }
857
858 // check that arguments array is not null
859 var chckArgsLabel = il.DefineLabel();
860 il.Emit(OpCodes.Ldarg_0);
861 il.Emit(OpCodes.Ldnull);
862 il.EmitBne_Un(chckArgsLabel);
863 il.Emit(OpCodes.Ldstr, "wrong number of arguments");
864 il.Emit(OpCodes.Newobj, FastMethodAccessorImpl.illegalArgumentExceptionWithMessageCtor);
865 il.Emit(OpCodes.Throw);
866
867 // parameters length must match number of parameters on array
868 il.MarkLabel(chckArgsLabel);
869 il.Emit(OpCodes.Ldarg_0);
870 il.Emit(OpCodes.Ldlen);
871 il.EmitLdc_I4(parameters.Length);
872 il.EmitBeq(convArgsLabel);
873 il.Emit(OpCodes.Ldstr, "wrong number of arguments");
874 il.Emit(OpCodes.Newobj, FastMethodAccessorImpl.illegalArgumentExceptionWithMessageCtor);
875 il.Emit(OpCodes.Throw);
876
877 // begin parameter conversion
878 il.MarkLabel(convArgsLabel);
879
880 // emit conversion code for the remainder of the arguments
881 for (var i = 0; i < parameters.Length; i++)
882 {
883 var tw = parameters[i];
884
885 // declare variable to hold argument
886 var o = p[n++] = il.AllocTempLocal(tw.TypeAsSignatureType);
887
888 // temporary variable for exceptions
889 var e = il.AllocTempLocal(typeof(Exception));
890
891 // load and convert argument
892 var endConvArgn = il.DefineLabel();
893 il.BeginExceptionBlock();
894 il.Emit(OpCodes.Ldarg_0);
895 il.EmitLdc_I4(i);
896 il.Emit(OpCodes.Ldelem_Ref);
897 BoxUtil.EmitUnboxArg(il, tw);
898 tw.EmitConvStackTypeToSignatureType(il, null);
899 il.Emit(OpCodes.Stloc, o);
900 il.EmitLeave(endConvArgn);
901
902 // catch InvalidCastException, store, add message, and wrap with IllegalArgumentException
903 il.BeginCatchBlock(typeof(InvalidCastException));
904 il.Emit(OpCodes.Stloc, e);
905 il.Emit(OpCodes.Ldstr, $"argument type mismatch on parameter {i}");
906 il.Emit(OpCodes.Ldloc, e);
907 il.Emit(OpCodes.Newobj, FastMethodAccessorImpl.illegalArgumentExceptionWithMessageAndCauseCtor);
908 il.Emit(OpCodes.Throw);
909
910 // catch Exception, wrap with IllegalArgumentException
911 il.BeginCatchBlock(typeof(Exception));
912 il.Emit(OpCodes.Stloc, e);
913 il.Emit(OpCodes.Ldstr, $"exception on parameter {i}");
914 il.Emit(OpCodes.Ldloc, e);
915 il.Emit(OpCodes.Newobj, FastMethodAccessorImpl.illegalArgumentExceptionWithMessageAndCauseCtor);
916 il.Emit(OpCodes.Throw);
917
918 // end of convert self block
919 il.EndExceptionBlock();
920 il.MarkLabel(endConvArgn);
921 il.ReleaseTempLocal(e);
922 }
923
924 // handle exceptions in constructor
925 il.BeginExceptionBlock();
926
927 // load converted arguments
928 for (int i = 0; i < n; i++)
929 {
930 il.Emit(OpCodes.Ldloc, p[i]);
931 il.ReleaseTempLocal(p[i]);
932 }
933
934 // call constructor
935 var rt = il.AllocTempLocal(typeof(object));
936 mw.EmitNewobj(il);
937 il.Emit(OpCodes.Stloc, rt);
938 il.EmitLeave(postLabel);
939
940 // catch exception from call and wrap
941 il.BeginCatchBlock(typeof(Exception));
942 il.Emit(OpCodes.Ldc_I4_0);
943 il.Emit(OpCodes.Call, il.Context.ByteCodeHelperMethods.MapException.MakeGenericMethod(il.Context.Types.Exception));
944 il.Emit(OpCodes.Newobj, FastMethodAccessorImpl.invocationTargetExceptionWithCauseCtor);
945 il.Emit(OpCodes.Throw);
946 il.EndExceptionBlock();
947
948 // return from method with last return value
949 il.MarkLabel(postLabel);
950 il.Emit(OpCodes.Ldloc, rt);
951 il.ReleaseTempLocal(rt);
952 il.Emit(OpCodes.Ret);
953 il.DoEmit();
954
955 // generate invoker
956 invoker = (Invoker)dm.CreateDelegate(typeof(Invoker));
957 }
959 {
960 throw e.ToJava();
961 }
962 }
963
964 [IKVM.Attributes.HideFromJava]
965 public object newInstance(object[] args)
966 {
967 try
968 {
969 return invoker(args);
970 }
971 catch (MethodAccessException e)
972 {
973 // this can happen if we're calling a non-public method and the call stack doesn't have ReflectionPermission.MemberAccess
974 throw new global::java.lang.IllegalAccessException().initCause(e);
975 }
976 }
977
978 }
979
980 sealed class FastSerializationConstructorAccessorImpl : global::sun.reflect.ConstructorAccessor
981 {
982
983 static readonly MethodInfo GetTypeFromHandleMethod = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle), new[] { typeof(RuntimeTypeHandle) });
984#if NETFRAMEWORK
985 static readonly MethodInfo GetUninitializedObjectMethod = typeof(FormatterServices).GetMethod(nameof(FormatterServices.GetUninitializedObject), new[] { typeof(Type) });
986#else
987 static readonly MethodInfo GetUninitializedObjectMethod = typeof(RuntimeHelpers).GetMethod(nameof(RuntimeHelpers.GetUninitializedObject), new[] { typeof(Type) });
988#endif
989 delegate object InvokeCtor();
990 InvokeCtor invoker;
991
992 internal FastSerializationConstructorAccessorImpl(global::java.lang.reflect.Constructor constructorToCall, global::java.lang.Class classToInstantiate)
993 {
994 RuntimeJavaMethod constructor = RuntimeJavaMethod.FromExecutable(constructorToCall);
995 if (constructor.GetParameters().Length != 0)
996 {
997 throw new NotImplementedException("Serialization constructor cannot have parameters");
998 }
999 constructor.Link();
1000 constructor.ResolveMethod();
1001 Type type;
1002 try
1003 {
1004 RuntimeJavaType wrapper = RuntimeJavaType.FromClass(classToInstantiate);
1005 wrapper.Finish();
1006 type = wrapper.TypeAsBaseType;
1007 }
1009 {
1010 throw x.ToJava();
1011 }
1012 DynamicMethod dm = DynamicMethodUtil.Create("__<SerializationCtor>", constructor.DeclaringType.TypeAsBaseType, true, typeof(object), null);
1013 CodeEmitter ilgen = JVM.Context.CodeEmitterFactory.Create(dm);
1014 ilgen.Emit(OpCodes.Ldtoken, type);
1015 ilgen.Emit(OpCodes.Call, GetTypeFromHandleMethod);
1016 ilgen.Emit(OpCodes.Call, GetUninitializedObjectMethod);
1017 ilgen.Emit(OpCodes.Dup);
1018 constructor.EmitCall(ilgen);
1019 ilgen.Emit(OpCodes.Ret);
1020 ilgen.DoEmit();
1021 invoker = (InvokeCtor)dm.CreateDelegate(typeof(InvokeCtor));
1022 }
1023
1024 [IKVM.Attributes.HideFromJava]
1025 public object newInstance(object[] args)
1026 {
1027 try
1028 {
1029 return invoker();
1030 }
1031 catch (MethodAccessException x)
1032 {
1033 // this can happen if we're calling a non-public method and the call stack doesn't have ReflectionPermission.MemberAccess
1034 throw new global::java.lang.IllegalAccessException().initCause(x);
1035 }
1036 }
1037 }
1038#endif // !NO_REF_EMIT
1039
1040 sealed class ActivatorConstructorAccessor : global::sun.reflect.ConstructorAccessor
1041 {
1042
1043 private readonly Type type;
1044
1045 internal ActivatorConstructorAccessor(RuntimeJavaMethod mw)
1046 {
1047 this.type = mw.DeclaringType.TypeAsBaseType;
1048 }
1049
1050 public object newInstance(object[] objarr)
1051 {
1052 if (objarr != null && objarr.Length != 0)
1053 throw new global::java.lang.IllegalArgumentException();
1054
1055 try
1056 {
1057 return Activator.CreateInstance(type);
1058 }
1059 catch (TargetInvocationException x)
1060 {
1061 throw new global::java.lang.reflect.InvocationTargetException(global::ikvm.runtime.Util.mapException(x.InnerException));
1062 }
1063 }
1064
1065 internal static bool IsSuitable(RuntimeJavaMethod mw)
1066 {
1067 var mb = mw.GetMethod();
1068 return mb != null
1069 && mb.IsConstructor
1070 && mb.IsPublic
1071 && mb.DeclaringType.IsPublic
1072 && mb.DeclaringType == mw.DeclaringType.TypeAsBaseType
1073 && mb.GetParameters().Length == 0;
1074 }
1075
1076 }
1077
1078 private abstract class FieldAccessorImplBase : global::sun.reflect.FieldAccessor, IReflectionException
1079 {
1080
1081 protected static readonly ushort inflationThreshold = 15;
1082 protected readonly RuntimeJavaField fw;
1083 protected readonly bool isFinal;
1084 protected ushort numInvocations;
1085
1089 static FieldAccessorImplBase()
1090 {
1091 if (global::java.security.AccessController.doPrivileged(new FuncPrivilegedAction<string>(() => SystemAccessor.InvokeGetProperty("ikvm.reflect.field.inflationThreshold"))) is string s && ushort.TryParse(s, out var value))
1092 inflationThreshold = value;
1093 }
1094
1100 FieldAccessorImplBase(RuntimeJavaField fw, bool isFinal)
1101 {
1102 this.fw = fw;
1103 this.isFinal = isFinal;
1104 }
1105
1106 private string GetQualifiedFieldName()
1107 {
1108 return fw.DeclaringType.Name + "." + fw.Name;
1109 }
1110
1111 private string GetFieldTypeName()
1112 {
1113 return fw.FieldTypeWrapper.IsPrimitive
1114 ? fw.FieldTypeWrapper.ClassObject.getName()
1115 : fw.FieldTypeWrapper.Name;
1116 }
1117
1118 public global::java.lang.IllegalArgumentException GetIllegalArgumentException(object obj)
1119 {
1120 // LAME like JDK 6 we return the wrong exception message (talking about setting the field, instead of getting)
1121 return SetIllegalArgumentException(obj);
1122 }
1123
1124 public global::java.lang.IllegalArgumentException SetIllegalArgumentException(object obj)
1125 {
1126 // LAME like JDK 6 we return the wrong exception message (when obj is the object, instead of the value)
1127 return SetIllegalArgumentException(obj != null ? global::ikvm.runtime.Util.getClassFromObject(obj).getName() : "", "");
1128 }
1129
1130 private global::java.lang.IllegalArgumentException SetIllegalArgumentException(string attemptedType, string attemptedValue)
1131 {
1132 return new global::java.lang.IllegalArgumentException(GetSetMessage(attemptedType, attemptedValue));
1133 }
1134
1135 protected global::java.lang.IllegalAccessException FinalFieldIllegalAccessException(object obj)
1136 {
1137 return FinalFieldIllegalAccessException(obj != null ? global::ikvm.runtime.Util.getClassFromObject(obj).getName() : "", "");
1138 }
1139
1140 private global::java.lang.IllegalAccessException FinalFieldIllegalAccessException(string attemptedType, string attemptedValue)
1141 {
1142 return new global::java.lang.IllegalAccessException(GetSetMessage(attemptedType, attemptedValue));
1143 }
1144
1145 private global::java.lang.IllegalArgumentException GetIllegalArgumentException(string type)
1146 {
1147 return new global::java.lang.IllegalArgumentException("Attempt to get " + GetFieldTypeName() + " field \"" + GetQualifiedFieldName() + "\" with illegal data type conversion to " + type);
1148 }
1149
1150 // this message comes from global::sun.reflect.UnsafeFieldAccessorImpl
1151 private string GetSetMessage(String attemptedType, String attemptedValue)
1152 {
1153 String err = "Can not set";
1154 if (fw.IsStatic)
1155 err += " static";
1156 if (isFinal)
1157 err += " final";
1158 err += " " + GetFieldTypeName() + " field " + GetQualifiedFieldName() + " to ";
1159 if (attemptedValue.Length > 0)
1160 {
1161 err += "(" + attemptedType + ")" + attemptedValue;
1162 }
1163 else
1164 {
1165 if (attemptedType.Length > 0)
1166 err += attemptedType;
1167 else
1168 err += "null value";
1169 }
1170 return err;
1171 }
1172
1173 public virtual bool getBoolean(object obj)
1174 {
1175 throw GetIllegalArgumentException("boolean");
1176 }
1177
1178 public virtual byte getByte(object obj)
1179 {
1180 throw GetIllegalArgumentException("byte");
1181 }
1182
1183 public virtual char getChar(object obj)
1184 {
1185 throw GetIllegalArgumentException("char");
1186 }
1187
1188 public virtual short getShort(object obj)
1189 {
1190 throw GetIllegalArgumentException("short");
1191 }
1192
1193 public virtual int getInt(object obj)
1194 {
1195 throw GetIllegalArgumentException("int");
1196 }
1197
1198 public virtual long getLong(object obj)
1199 {
1200 throw GetIllegalArgumentException("long");
1201 }
1202
1203 public virtual float getFloat(object obj)
1204 {
1205 throw GetIllegalArgumentException("float");
1206 }
1207
1208 public virtual double getDouble(object obj)
1209 {
1210 throw GetIllegalArgumentException("double");
1211 }
1212
1213 public virtual void setBoolean(object obj, bool z)
1214 {
1215 throw SetIllegalArgumentException("boolean", global::java.lang.Boolean.toString(z));
1216 }
1217
1218 public virtual void setByte(object obj, byte b)
1219 {
1220 throw SetIllegalArgumentException("byte", global::java.lang.Byte.toString(b));
1221 }
1222
1223 public virtual void setChar(object obj, char c)
1224 {
1225 throw SetIllegalArgumentException("char", global::java.lang.Character.toString(c));
1226 }
1227
1228 public virtual void setShort(object obj, short s)
1229 {
1230 throw SetIllegalArgumentException("short", global::java.lang.Short.toString(s));
1231 }
1232
1233 public virtual void setInt(object obj, int i)
1234 {
1235 throw SetIllegalArgumentException("int", global::java.lang.Integer.toString(i));
1236 }
1237
1238 public virtual void setLong(object obj, long l)
1239 {
1240 throw SetIllegalArgumentException("long", global::java.lang.Long.toString(l));
1241 }
1242
1243 public virtual void setFloat(object obj, float f)
1244 {
1245 throw SetIllegalArgumentException("float", global::java.lang.Float.toString(f));
1246 }
1247
1248 public virtual void setDouble(object obj, double d)
1249 {
1250 throw SetIllegalArgumentException("double", global::java.lang.Double.toString(d));
1251 }
1252
1253 public abstract object get(object obj);
1254 public abstract void set(object obj, object value);
1255
1256 private abstract class FieldAccessor<T> : FieldAccessorImplBase
1257 {
1258
1259 static readonly RuntimeContext context = JVM.Context;
1260
1261 protected delegate void Setter(object obj, T value, FieldAccessor<T> acc);
1262 protected delegate T Getter(object obj, FieldAccessor<T> acc);
1263 private static readonly Setter initialSetter = lazySet;
1264 private static readonly Getter initialGetter = lazyGet;
1265 protected Setter setter = initialSetter;
1266 protected Getter getter = initialGetter;
1267
1268 internal FieldAccessor(RuntimeJavaField fw, bool isFinal)
1269 : base(fw, isFinal)
1270 {
1271 if (!IsSlowPathCompatible(fw))
1272 {
1273 // prevent slow path
1274 numInvocations = inflationThreshold;
1275 }
1276 }
1277
1278 private bool IsSlowPathCompatible(RuntimeJavaField fw)
1279 {
1280#if !NO_REF_EMIT
1281 if (fw.IsVolatile && (fw.FieldTypeWrapper == context.PrimitiveJavaTypeFactory.LONG || fw.FieldTypeWrapper == context.PrimitiveJavaTypeFactory.DOUBLE))
1282 {
1283 return false;
1284 }
1285#endif
1286 fw.Link();
1287 return true;
1288 }
1289
1290 private static T lazyGet(object obj, FieldAccessor<T> acc)
1291 {
1292 return acc.lazyGet(obj);
1293 }
1294
1295 private static void lazySet(object obj, T value, FieldAccessor<T> acc)
1296 {
1297 acc.lazySet(obj, value);
1298 }
1299
1300 private T lazyGet(object obj)
1301 {
1302#if !NO_REF_EMIT
1303 if (numInvocations >= inflationThreshold)
1304 {
1305 // FXBUG it appears that a ldsfld/stsfld in a DynamicMethod doesn't trigger the class constructor
1306 // and if we didn't use the slow path, we haven't yet initialized the class
1307 fw.DeclaringType.RunClassInit();
1308 getter = (Getter)GenerateFastGetter(typeof(Getter), typeof(T), fw);
1309 return getter(obj, this);
1310 }
1311#endif // !NO_REF_EMIT
1312 if (fw.IsStatic)
1313 {
1314 obj = null;
1315 }
1316 else if (obj == null)
1317 {
1318 throw new global::java.lang.NullPointerException();
1319 }
1320 else if (!fw.DeclaringType.IsInstance(obj))
1321 {
1322 throw GetIllegalArgumentException(obj);
1323 }
1324 else if (fw.DeclaringType.IsRemapped && !fw.DeclaringType.TypeAsBaseType.IsInstanceOfType(obj))
1325 {
1326 throw GetUnsupportedRemappedFieldException(obj);
1327 }
1328 if (numInvocations == 0)
1329 {
1330 fw.DeclaringType.RunClassInit();
1331 fw.DeclaringType.Finish();
1332 fw.ResolveField();
1333 }
1334 numInvocations++;
1335 return (T)fw.FieldTypeWrapper.GhostUnwrap(fw.GetValue(obj));
1336 }
1337
1338 private void lazySet(object obj, T value)
1339 {
1340 if (isFinal)
1341 {
1342 // for some reason Java runs class initialization before checking if the field is final
1343 fw.DeclaringType.RunClassInit();
1344 throw FinalFieldIllegalAccessException(JavaBox(value));
1345 }
1346#if !NO_REF_EMIT
1347 if (numInvocations >= inflationThreshold)
1348 {
1349 // FXBUG it appears that a ldsfld/stsfld in a DynamicMethod doesn't trigger the class constructor
1350 // and if we didn't use the slow path, we haven't yet initialized the class
1351 fw.DeclaringType.RunClassInit();
1352 setter = (Setter)GenerateFastSetter(typeof(Setter), typeof(T), fw);
1353 setter(obj, value, this);
1354 return;
1355 }
1356#endif // !NO_REF_EMIT
1357 if (fw.IsStatic)
1358 {
1359 obj = null;
1360 }
1361 else if (obj == null)
1362 {
1363 throw new global::java.lang.NullPointerException();
1364 }
1365 else if (!fw.DeclaringType.IsInstance(obj))
1366 {
1367 throw SetIllegalArgumentException(obj);
1368 }
1369 else if (fw.DeclaringType.IsRemapped && !fw.DeclaringType.TypeAsBaseType.IsInstanceOfType(obj))
1370 {
1371 throw GetUnsupportedRemappedFieldException(obj);
1372 }
1373 CheckValue(value);
1374 if (numInvocations == 0)
1375 {
1376 fw.DeclaringType.RunClassInit();
1377 fw.DeclaringType.Finish();
1378 fw.ResolveField();
1379 }
1380 numInvocations++;
1381 fw.SetValue(obj, fw.FieldTypeWrapper.GhostWrap(value));
1382 }
1383
1384 private Exception GetUnsupportedRemappedFieldException(object obj)
1385 {
1386 return new global::java.lang.IllegalAccessException("Accessing field " + fw.DeclaringType.Name + "." + fw.Name + " in an object of type " + global::ikvm.runtime.Util.getClassFromObject(obj).getName() + " is not supported");
1387 }
1388
1389 protected virtual void CheckValue(T value)
1390 {
1391 }
1392
1393 protected abstract object JavaBox(T value);
1394 }
1395
1396 private sealed class ByteField : FieldAccessor<byte>
1397 {
1398 internal ByteField(RuntimeJavaField field, bool isFinal)
1399 : base(field, isFinal)
1400 {
1401 }
1402
1403 public sealed override short getShort(object obj)
1404 {
1405 return (sbyte)getByte(obj);
1406 }
1407
1408 public sealed override int getInt(object obj)
1409 {
1410 return (sbyte)getByte(obj);
1411 }
1412
1413 public sealed override long getLong(object obj)
1414 {
1415 return (sbyte)getByte(obj);
1416 }
1417
1418 public sealed override float getFloat(object obj)
1419 {
1420 return (sbyte)getByte(obj);
1421 }
1422
1423 public sealed override double getDouble(object obj)
1424 {
1425 return (sbyte)getByte(obj);
1426 }
1427
1428 public sealed override object get(object obj)
1429 {
1430 return global::java.lang.Byte.valueOf(getByte(obj));
1431 }
1432
1433 public sealed override void set(object obj, object val)
1434 {
1435 if (!(val is global::java.lang.Byte))
1436 {
1437 throw SetIllegalArgumentException(val);
1438 }
1439 setByte(obj, ((global::java.lang.Byte)val).byteValue());
1440 }
1441
1442 public sealed override byte getByte(object obj)
1443 {
1444 try
1445 {
1446 return getter(obj, this);
1447 }
1448 catch (FieldAccessException x)
1449 {
1450 throw new global::java.lang.IllegalAccessException().initCause(x);
1451 }
1452 }
1453
1454 public sealed override void setByte(object obj, byte value)
1455 {
1456 try
1457 {
1458 setter(obj, value, this);
1459 }
1460 catch (FieldAccessException x)
1461 {
1462 throw new global::java.lang.IllegalAccessException().initCause(x);
1463 }
1464 }
1465
1466 protected sealed override object JavaBox(byte value)
1467 {
1468 return global::java.lang.Byte.valueOf(value);
1469 }
1470 }
1471
1472 private sealed class BooleanField : FieldAccessor<bool>
1473 {
1474 internal BooleanField(RuntimeJavaField field, bool isFinal)
1475 : base(field, isFinal)
1476 {
1477 }
1478
1479 public sealed override object get(object obj)
1480 {
1481 return global::java.lang.Boolean.valueOf(getBoolean(obj));
1482 }
1483
1484 public sealed override void set(object obj, object val)
1485 {
1486 if (!(val is global::java.lang.Boolean))
1487 {
1488 throw SetIllegalArgumentException(val);
1489 }
1490 setBoolean(obj, ((global::java.lang.Boolean)val).booleanValue());
1491 }
1492
1493 public sealed override bool getBoolean(object obj)
1494 {
1495 try
1496 {
1497 return getter(obj, this);
1498 }
1499 catch (FieldAccessException x)
1500 {
1501 throw new global::java.lang.IllegalAccessException().initCause(x);
1502 }
1503 }
1504
1505 public sealed override void setBoolean(object obj, bool value)
1506 {
1507 try
1508 {
1509 setter(obj, value, this);
1510 }
1511 catch (FieldAccessException x)
1512 {
1513 throw new global::java.lang.IllegalAccessException().initCause(x);
1514 }
1515 }
1516
1517 protected sealed override object JavaBox(bool value)
1518 {
1519 return global::java.lang.Boolean.valueOf(value);
1520 }
1521 }
1522
1523 private sealed class CharField : FieldAccessor<char>
1524 {
1525 internal CharField(RuntimeJavaField field, bool isFinal)
1526 : base(field, isFinal)
1527 {
1528 }
1529
1530 public sealed override int getInt(object obj)
1531 {
1532 return getChar(obj);
1533 }
1534
1535 public sealed override long getLong(object obj)
1536 {
1537 return getChar(obj);
1538 }
1539
1540 public sealed override float getFloat(object obj)
1541 {
1542 return getChar(obj);
1543 }
1544
1545 public sealed override double getDouble(object obj)
1546 {
1547 return getChar(obj);
1548 }
1549
1550 public sealed override object get(object obj)
1551 {
1552 return global::java.lang.Character.valueOf(getChar(obj));
1553 }
1554
1555 public sealed override void set(object obj, object val)
1556 {
1557 if (val is global::java.lang.Character)
1558 setChar(obj, ((global::java.lang.Character)val).charValue());
1559 else
1560 throw SetIllegalArgumentException(val);
1561 }
1562
1563 public sealed override char getChar(object obj)
1564 {
1565 try
1566 {
1567 return getter(obj, this);
1568 }
1569 catch (FieldAccessException x)
1570 {
1571 throw new global::java.lang.IllegalAccessException().initCause(x);
1572 }
1573 }
1574
1575 public sealed override void setChar(object obj, char value)
1576 {
1577 try
1578 {
1579 setter(obj, value, this);
1580 }
1581 catch (FieldAccessException x)
1582 {
1583 throw new global::java.lang.IllegalAccessException().initCause(x);
1584 }
1585 }
1586
1587 protected sealed override object JavaBox(char value)
1588 {
1589 return global::java.lang.Character.valueOf(value);
1590 }
1591 }
1592
1593 private sealed class ShortField : FieldAccessor<short>
1594 {
1595 internal ShortField(RuntimeJavaField field, bool isFinal)
1596 : base(field, isFinal)
1597 {
1598 }
1599
1600 public sealed override int getInt(object obj)
1601 {
1602 return getShort(obj);
1603 }
1604
1605 public sealed override long getLong(object obj)
1606 {
1607 return getShort(obj);
1608 }
1609
1610 public sealed override float getFloat(object obj)
1611 {
1612 return getShort(obj);
1613 }
1614
1615 public sealed override double getDouble(object obj)
1616 {
1617 return getShort(obj);
1618 }
1619
1620 public sealed override object get(object obj)
1621 {
1622 return global::java.lang.Short.valueOf(getShort(obj));
1623 }
1624
1625 public sealed override void set(object obj, object val)
1626 {
1627 if (val is global::java.lang.Byte
1628 || val is global::java.lang.Short)
1629 setShort(obj, ((global::java.lang.Number)val).shortValue());
1630 else
1631 throw SetIllegalArgumentException(val);
1632 }
1633
1634 public sealed override void setByte(object obj, byte b)
1635 {
1636 setShort(obj, (sbyte)b);
1637 }
1638
1639 public sealed override short getShort(object obj)
1640 {
1641 try
1642 {
1643 return getter(obj, this);
1644 }
1645 catch (FieldAccessException x)
1646 {
1647 throw new global::java.lang.IllegalAccessException().initCause(x);
1648 }
1649 }
1650
1651 public sealed override void setShort(object obj, short value)
1652 {
1653 try
1654 {
1655 setter(obj, value, this);
1656 }
1657 catch (FieldAccessException x)
1658 {
1659 throw new global::java.lang.IllegalAccessException().initCause(x);
1660 }
1661 }
1662
1663 protected sealed override object JavaBox(short value)
1664 {
1665 return global::java.lang.Short.valueOf(value);
1666 }
1667 }
1668
1669 private sealed class IntField : FieldAccessor<int>
1670 {
1671 internal IntField(RuntimeJavaField field, bool isFinal)
1672 : base(field, isFinal)
1673 {
1674 }
1675
1676 public sealed override long getLong(object obj)
1677 {
1678 return getInt(obj);
1679 }
1680
1681 public sealed override float getFloat(object obj)
1682 {
1683 return getInt(obj);
1684 }
1685
1686 public sealed override double getDouble(object obj)
1687 {
1688 return getInt(obj);
1689 }
1690
1691 public sealed override object get(object obj)
1692 {
1693 return global::java.lang.Integer.valueOf(getInt(obj));
1694 }
1695
1696 public sealed override void set(object obj, object val)
1697 {
1698 if (val is global::java.lang.Byte
1699 || val is global::java.lang.Short
1700 || val is global::java.lang.Integer)
1701 setInt(obj, ((global::java.lang.Number)val).intValue());
1702 else if (val is global::java.lang.Character)
1703 setInt(obj, ((global::java.lang.Character)val).charValue());
1704 else
1705 throw SetIllegalArgumentException(val);
1706 }
1707
1708 public sealed override void setByte(object obj, byte b)
1709 {
1710 setInt(obj, (sbyte)b);
1711 }
1712
1713 public sealed override void setChar(object obj, char c)
1714 {
1715 setInt(obj, c);
1716 }
1717
1718 public sealed override void setShort(object obj, short s)
1719 {
1720 setInt(obj, s);
1721 }
1722
1723 public sealed override int getInt(object obj)
1724 {
1725 try
1726 {
1727 return getter(obj, this);
1728 }
1729 catch (FieldAccessException x)
1730 {
1731 throw new global::java.lang.IllegalAccessException().initCause(x);
1732 }
1733 }
1734
1735 public sealed override void setInt(object obj, int value)
1736 {
1737 try
1738 {
1739 setter(obj, value, this);
1740 }
1741 catch (FieldAccessException x)
1742 {
1743 throw new global::java.lang.IllegalAccessException().initCause(x);
1744 }
1745 }
1746
1747 protected sealed override object JavaBox(int value)
1748 {
1749 return global::java.lang.Integer.valueOf(value);
1750 }
1751 }
1752
1753 private sealed class FloatField : FieldAccessor<float>
1754 {
1755 internal FloatField(RuntimeJavaField field, bool isFinal)
1756 : base(field, isFinal)
1757 {
1758 }
1759
1760 public sealed override double getDouble(object obj)
1761 {
1762 return getFloat(obj);
1763 }
1764
1765 public sealed override object get(object obj)
1766 {
1767 return global::java.lang.Float.valueOf(getFloat(obj));
1768 }
1769
1770 public sealed override void set(object obj, object val)
1771 {
1772 if (val is global::java.lang.Float
1773 || val is global::java.lang.Byte
1774 || val is global::java.lang.Short
1775 || val is global::java.lang.Integer
1776 || val is global::java.lang.Long)
1777 setFloat(obj, ((global::java.lang.Number)val).floatValue());
1778 else if (val is global::java.lang.Character)
1779 setFloat(obj, ((global::java.lang.Character)val).charValue());
1780 else
1781 throw SetIllegalArgumentException(val);
1782 }
1783
1784 public sealed override void setByte(object obj, byte b)
1785 {
1786 setFloat(obj, (sbyte)b);
1787 }
1788
1789 public sealed override void setChar(object obj, char c)
1790 {
1791 setFloat(obj, c);
1792 }
1793
1794 public sealed override void setShort(object obj, short s)
1795 {
1796 setFloat(obj, s);
1797 }
1798
1799 public sealed override void setInt(object obj, int i)
1800 {
1801 setFloat(obj, i);
1802 }
1803
1804 public sealed override void setLong(object obj, long l)
1805 {
1806 setFloat(obj, l);
1807 }
1808
1809 public sealed override float getFloat(object obj)
1810 {
1811 try
1812 {
1813 return getter(obj, this);
1814 }
1815 catch (FieldAccessException x)
1816 {
1817 throw new global::java.lang.IllegalAccessException().initCause(x);
1818 }
1819 }
1820
1821 public sealed override void setFloat(object obj, float value)
1822 {
1823 try
1824 {
1825 setter(obj, value, this);
1826 }
1827 catch (FieldAccessException x)
1828 {
1829 throw new global::java.lang.IllegalAccessException().initCause(x);
1830 }
1831 }
1832
1833 protected sealed override object JavaBox(float value)
1834 {
1835 return global::java.lang.Float.valueOf(value);
1836 }
1837 }
1838
1839 private sealed class LongField : FieldAccessor<long>
1840 {
1841 internal LongField(RuntimeJavaField field, bool isFinal)
1842 : base(field, isFinal)
1843 {
1844 }
1845
1846 public sealed override float getFloat(object obj)
1847 {
1848 return getLong(obj);
1849 }
1850
1851 public sealed override double getDouble(object obj)
1852 {
1853 return getLong(obj);
1854 }
1855
1856 public sealed override object get(object obj)
1857 {
1858 return global::java.lang.Long.valueOf(getLong(obj));
1859 }
1860
1861 public sealed override void set(object obj, object val)
1862 {
1863 if (val is global::java.lang.Long
1864 || val is global::java.lang.Byte
1865 || val is global::java.lang.Short
1866 || val is global::java.lang.Integer)
1867 setLong(obj, ((global::java.lang.Number)val).longValue());
1868 else if (val is global::java.lang.Character)
1869 setLong(obj, ((global::java.lang.Character)val).charValue());
1870 else
1871 throw SetIllegalArgumentException(val);
1872 }
1873
1874 public sealed override void setByte(object obj, byte b)
1875 {
1876 setLong(obj, (sbyte)b);
1877 }
1878
1879 public sealed override void setChar(object obj, char c)
1880 {
1881 setLong(obj, c);
1882 }
1883
1884 public sealed override void setShort(object obj, short s)
1885 {
1886 setLong(obj, s);
1887 }
1888
1889 public sealed override void setInt(object obj, int i)
1890 {
1891 setLong(obj, i);
1892 }
1893
1894 public sealed override long getLong(object obj)
1895 {
1896 try
1897 {
1898 return getter(obj, this);
1899 }
1900 catch (FieldAccessException x)
1901 {
1902 throw new global::java.lang.IllegalAccessException().initCause(x);
1903 }
1904 }
1905
1906 public sealed override void setLong(object obj, long value)
1907 {
1908 try
1909 {
1910 setter(obj, value, this);
1911 }
1912 catch (FieldAccessException x)
1913 {
1914 throw new global::java.lang.IllegalAccessException().initCause(x);
1915 }
1916 }
1917
1918 protected sealed override object JavaBox(long value)
1919 {
1920 return global::java.lang.Long.valueOf(value);
1921 }
1922 }
1923
1924 private sealed class DoubleField : FieldAccessor<double>
1925 {
1926 internal DoubleField(RuntimeJavaField field, bool isFinal)
1927 : base(field, isFinal)
1928 {
1929 }
1930
1931 public sealed override object get(object obj)
1932 {
1933 return global::java.lang.Double.valueOf(getDouble(obj));
1934 }
1935
1936 public sealed override void set(object obj, object val)
1937 {
1938 if (val is global::java.lang.Double
1939 || val is global::java.lang.Float
1940 || val is global::java.lang.Byte
1941 || val is global::java.lang.Short
1942 || val is global::java.lang.Integer
1943 || val is global::java.lang.Long)
1944 setDouble(obj, ((global::java.lang.Number)val).doubleValue());
1945 else if (val is global::java.lang.Character)
1946 setDouble(obj, ((global::java.lang.Character)val).charValue());
1947 else
1948 throw SetIllegalArgumentException(val);
1949 }
1950
1951 public sealed override void setByte(object obj, byte b)
1952 {
1953 setDouble(obj, (sbyte)b);
1954 }
1955
1956 public sealed override void setChar(object obj, char c)
1957 {
1958 setDouble(obj, c);
1959 }
1960
1961 public sealed override void setShort(object obj, short s)
1962 {
1963 setDouble(obj, s);
1964 }
1965
1966 public sealed override void setInt(object obj, int i)
1967 {
1968 setDouble(obj, i);
1969 }
1970
1971 public sealed override void setLong(object obj, long l)
1972 {
1973 setDouble(obj, l);
1974 }
1975
1976 public sealed override void setFloat(object obj, float f)
1977 {
1978 setDouble(obj, f);
1979 }
1980
1981 public sealed override double getDouble(object obj)
1982 {
1983 try
1984 {
1985 return getter(obj, this);
1986 }
1987 catch (FieldAccessException x)
1988 {
1989 throw new global::java.lang.IllegalAccessException().initCause(x);
1990 }
1991 }
1992
1993 public sealed override void setDouble(object obj, double value)
1994 {
1995 try
1996 {
1997 setter(obj, value, this);
1998 }
1999 catch (FieldAccessException x)
2000 {
2001 throw new global::java.lang.IllegalAccessException().initCause(x);
2002 }
2003 }
2004
2005 protected sealed override object JavaBox(double value)
2006 {
2007 return global::java.lang.Double.valueOf(value);
2008 }
2009 }
2010
2011 private sealed class ObjectField : FieldAccessor<object>
2012 {
2013 internal ObjectField(RuntimeJavaField field, bool isFinal)
2014 : base(field, isFinal)
2015 {
2016 }
2017
2018 protected sealed override void CheckValue(object value)
2019 {
2020 if (value != null && !fw.FieldTypeWrapper.EnsureLoadable(fw.DeclaringType.ClassLoader).IsInstance(value))
2021 {
2022 throw SetIllegalArgumentException(value);
2023 }
2024 }
2025
2026 public sealed override object get(object obj)
2027 {
2028 try
2029 {
2030 return getter(obj, this);
2031 }
2032 catch (FieldAccessException x)
2033 {
2034 throw new global::java.lang.IllegalAccessException().initCause(x);
2035 }
2036 }
2037
2038 public sealed override void set(object obj, object value)
2039 {
2040 try
2041 {
2042 setter(obj, value, this);
2043 }
2044 catch (FieldAccessException x)
2045 {
2046 throw new global::java.lang.IllegalAccessException().initCause(x);
2047 }
2048 }
2049
2050 protected sealed override object JavaBox(object value)
2051 {
2052 return value;
2053 }
2054 }
2055
2056#if !NO_REF_EMIT
2057 private Delegate GenerateFastGetter(Type delegateType, Type fieldType, RuntimeJavaField fw)
2058 {
2059 RuntimeJavaType fieldTypeWrapper;
2060 try
2061 {
2062 fieldTypeWrapper = fw.FieldTypeWrapper.EnsureLoadable(fw.DeclaringType.ClassLoader);
2063 fieldTypeWrapper.Finish();
2064 fw.DeclaringType.Finish();
2065 }
2067 {
2068 throw x.ToJava();
2069 }
2070 fw.ResolveField();
2071 DynamicMethod dm = DynamicMethodUtil.Create("__<Getter>", fw.DeclaringType.TypeAsBaseType, !fw.IsPublic || !fw.DeclaringType.IsPublic, fieldType, new Type[] { typeof(IReflectionException), typeof(object), typeof(object) });
2072 CodeEmitter ilgen = JVM.Context.CodeEmitterFactory.Create(dm);
2073 if (fw.IsStatic)
2074 {
2075 fw.EmitGet(ilgen);
2076 fieldTypeWrapper.EmitConvSignatureTypeToStackType(ilgen);
2077 }
2078 else
2079 {
2080 ilgen.BeginExceptionBlock();
2081 ilgen.Emit(OpCodes.Ldarg_1);
2082 ilgen.Emit(OpCodes.Castclass, fw.DeclaringType.TypeAsBaseType);
2083 fw.EmitGet(ilgen);
2084 fieldTypeWrapper.EmitConvSignatureTypeToStackType(ilgen);
2085 CodeEmitterLocal local = ilgen.DeclareLocal(fieldType);
2086 ilgen.Emit(OpCodes.Stloc, local);
2087 CodeEmitterLabel label = ilgen.DefineLabel();
2088 ilgen.EmitLeave(label);
2089 ilgen.BeginCatchBlock(typeof(InvalidCastException));
2090 ilgen.Emit(OpCodes.Ldarg_0);
2091 ilgen.Emit(OpCodes.Ldarg_1);
2092 ilgen.Emit(OpCodes.Callvirt, typeof(IReflectionException).GetMethod("GetIllegalArgumentException"));
2093 ilgen.Emit(OpCodes.Throw);
2094 ilgen.EndExceptionBlock();
2095 ilgen.MarkLabel(label);
2096 ilgen.Emit(OpCodes.Ldloc, local);
2097 }
2098 ilgen.Emit(OpCodes.Ret);
2099 ilgen.DoEmit();
2100 return dm.CreateDelegate(delegateType, this);
2101 }
2102
2103 private Delegate GenerateFastSetter(Type delegateType, Type fieldType, RuntimeJavaField fw)
2104 {
2105 RuntimeJavaType fieldTypeWrapper;
2106 try
2107 {
2108 fieldTypeWrapper = fw.FieldTypeWrapper.EnsureLoadable(fw.DeclaringType.ClassLoader);
2109 fieldTypeWrapper.Finish();
2110 fw.DeclaringType.Finish();
2111 }
2113 {
2114 throw x.ToJava();
2115 }
2116 fw.ResolveField();
2117 DynamicMethod dm = DynamicMethodUtil.Create("__<Setter>", fw.DeclaringType.TypeAsBaseType, !fw.IsPublic || !fw.DeclaringType.IsPublic, null, new Type[] { typeof(IReflectionException), typeof(object), fieldType, typeof(object) });
2118 CodeEmitter ilgen = JVM.Context.CodeEmitterFactory.Create(dm);
2119 if (fw.IsStatic)
2120 {
2121 if (fieldType == typeof(object))
2122 {
2123 ilgen.BeginExceptionBlock();
2124 ilgen.Emit(OpCodes.Ldarg_2);
2125 fieldTypeWrapper.EmitCheckcast(ilgen);
2126 fieldTypeWrapper.EmitConvStackTypeToSignatureType(ilgen, null);
2127 fw.EmitSet(ilgen);
2128 CodeEmitterLabel label = ilgen.DefineLabel();
2129 ilgen.EmitLeave(label);
2130 ilgen.BeginCatchBlock(typeof(InvalidCastException));
2131 ilgen.Emit(OpCodes.Ldarg_0);
2132 ilgen.Emit(OpCodes.Ldarg_1);
2133 ilgen.Emit(OpCodes.Callvirt, typeof(IReflectionException).GetMethod("SetIllegalArgumentException"));
2134 ilgen.Emit(OpCodes.Throw);
2135 ilgen.EndExceptionBlock();
2136 ilgen.MarkLabel(label);
2137 }
2138 else
2139 {
2140 ilgen.Emit(OpCodes.Ldarg_2);
2141 fw.EmitSet(ilgen);
2142 }
2143 }
2144 else
2145 {
2146 ilgen.BeginExceptionBlock();
2147 ilgen.Emit(OpCodes.Ldarg_1);
2148 ilgen.Emit(OpCodes.Castclass, fw.DeclaringType.TypeAsBaseType);
2149 ilgen.Emit(OpCodes.Ldarg_2);
2150 if (fieldType == typeof(object))
2151 {
2152 fieldTypeWrapper.EmitCheckcast(ilgen);
2153 }
2154 fieldTypeWrapper.EmitConvStackTypeToSignatureType(ilgen, null);
2155 fw.EmitSet(ilgen);
2156 CodeEmitterLabel label = ilgen.DefineLabel();
2157 ilgen.EmitLeave(label);
2158 ilgen.BeginCatchBlock(typeof(InvalidCastException));
2159 ilgen.Emit(OpCodes.Ldarg_0);
2160 ilgen.Emit(OpCodes.Ldarg_1);
2161 ilgen.Emit(OpCodes.Callvirt, typeof(IReflectionException).GetMethod("SetIllegalArgumentException"));
2162 ilgen.Emit(OpCodes.Throw);
2163 ilgen.EndExceptionBlock();
2164 ilgen.MarkLabel(label);
2165 }
2166 ilgen.Emit(OpCodes.Ret);
2167 ilgen.DoEmit();
2168 return dm.CreateDelegate(delegateType, this);
2169 }
2170#endif // !NO_REF_EMIT
2171
2172 internal static FieldAccessorImplBase Create(RuntimeJavaField field, bool isFinal)
2173 {
2174 RuntimeJavaType type = field.FieldTypeWrapper;
2175 if (type.IsPrimitive)
2176 {
2177 if (type == type.Context.PrimitiveJavaTypeFactory.BYTE)
2178 {
2179 return new ByteField(field, isFinal);
2180 }
2181 if (type == type.Context.PrimitiveJavaTypeFactory.BOOLEAN)
2182 {
2183 return new BooleanField(field, isFinal);
2184 }
2185 if (type == type.Context.PrimitiveJavaTypeFactory.CHAR)
2186 {
2187 return new CharField(field, isFinal);
2188 }
2189 if (type == type.Context.PrimitiveJavaTypeFactory.SHORT)
2190 {
2191 return new ShortField(field, isFinal);
2192 }
2193 if (type == type.Context.PrimitiveJavaTypeFactory.INT)
2194 {
2195 return new IntField(field, isFinal);
2196 }
2197 if (type == type.Context.PrimitiveJavaTypeFactory.FLOAT)
2198 {
2199 return new FloatField(field, isFinal);
2200 }
2201 if (type == type.Context.PrimitiveJavaTypeFactory.LONG)
2202 {
2203 return new LongField(field, isFinal);
2204 }
2205 if (type == type.Context.PrimitiveJavaTypeFactory.DOUBLE)
2206 {
2207 return new DoubleField(field, isFinal);
2208 }
2209 throw new InvalidOperationException("field type: " + type);
2210 }
2211 else
2212 {
2213 return new ObjectField(field, isFinal);
2214 }
2215 }
2216 }
2217#endif
2218
2219 public static global::sun.reflect.FieldAccessor newFieldAccessor(object thisFactory, global::java.lang.reflect.Field field, bool overrideAccessCheck)
2220 {
2221#if FIRST_PASS
2222 return null;
2223#else
2224 // we look at the modifiers of the Field object to allow Unsafe to give us a fake Field take doesn't have the final flag set
2225 int modifiers = field.getModifiers();
2226 bool isStatic = global::java.lang.reflect.Modifier.isStatic(modifiers);
2227 bool isFinal = global::java.lang.reflect.Modifier.isFinal(modifiers);
2228 return FieldAccessorImplBase.Create(RuntimeJavaField.FromField(field), isFinal && (!overrideAccessCheck || isStatic));
2229#endif
2230 }
2231
2232#if !FIRST_PASS
2233 internal static global::sun.reflect.FieldAccessor NewFieldAccessorJNI(RuntimeJavaField field)
2234 {
2235 return FieldAccessorImplBase.Create(field, false);
2236 }
2237#endif
2238
2239 public static global::sun.reflect.MethodAccessor newMethodAccessor(object thisFactory, global::java.lang.reflect.Method method)
2240 {
2241#if FIRST_PASS
2242 return null;
2243#else
2244 RuntimeJavaMethod mw = RuntimeJavaMethod.FromExecutable(method);
2245#if !NO_REF_EMIT
2246 if (!mw.IsDynamicOnly)
2247 {
2248 return new FastMethodAccessorImpl(mw);
2249 }
2250#endif
2251 return new MethodAccessorImpl(mw);
2252#endif
2253 }
2254
2255 public static global::sun.reflect.ConstructorAccessor newConstructorAccessor0(object thisFactory, global::java.lang.reflect.Constructor constructor)
2256 {
2257#if FIRST_PASS
2258 return null;
2259#else
2260 RuntimeJavaMethod mw = RuntimeJavaMethod.FromExecutable(constructor);
2261 if (ActivatorConstructorAccessor.IsSuitable(mw))
2262 {
2263 // we special case public default constructors, because in that case using Activator.CreateInstance()
2264 // is almost as fast as FastConstructorAccessorImpl, but it saves us significantly in working set and
2265 // startup time (because often during startup a sun.nio.cs.* encoder is instantiated using reflection)
2266 return new ActivatorConstructorAccessor(mw);
2267 }
2268 else
2269 {
2270#if NO_REF_EMIT
2271 return new ConstructorAccessorImpl(mw);
2272#else
2273 return new FastConstructorAccessorImpl(constructor);
2274#endif
2275 }
2276#endif
2277 }
2278
2279 public static global::sun.reflect.ConstructorAccessor newConstructorAccessorForSerialization(global::java.lang.Class classToInstantiate, global::java.lang.reflect.Constructor constructorToCall)
2280 {
2281#if FIRST_PASS
2282 return null;
2283#else
2284 try
2285 {
2286#if NO_REF_EMIT
2287 return new SerializationConstructorAccessorImpl(constructorToCall, classToInstantiate);
2288#else
2289 return new FastSerializationConstructorAccessorImpl(constructorToCall, classToInstantiate);
2290#endif
2291 }
2292 catch (SecurityException x)
2293 {
2294 throw new global::java.lang.SecurityException(x.Message, global::ikvm.runtime.Util.mapException(x));
2295 }
2296#endif
2297 }
2298
2299 }
2300
2301}
IKVM.Reflection.Type Type
IKVM.Reflection.ConstructorInfo ConstructorInfo
IKVM.Reflection.MethodInfo MethodInfo
static global::sun.reflect.FieldAccessor newFieldAccessor(object thisFactory, global::java.lang.reflect.Field field, bool overrideAccessCheck)
static global::sun.reflect.ConstructorAccessor newConstructorAccessorForSerialization(global::java.lang.Class classToInstantiate, global::java.lang.reflect.Constructor constructorToCall)
static global::sun.reflect.ConstructorAccessor newConstructorAccessor0(object thisFactory, global::java.lang.reflect.Constructor constructor)
static global::sun.reflect.MethodAccessor newMethodAccessor(object thisFactory, global::java.lang.reflect.Method method)
CodeEmitter Create(MethodBuilder mb)
Creates a new instance.
RuntimeContext Context
Gets the RuntimeContext that hosts this code emitter.
Provides utilities for working with dynamic methods.
Main state of the running JVM.
.NET exception that corresponds to a Java exception.
Runtime support for a class loader.
Maintains services relevant to an instane of the IKVM runtime.
CodeEmitterFactory CodeEmitterFactory
Gets the CodeEmitterFactory associated with this instance of the runtime.
RuntimePrimitiveJavaTypeFactory PrimitiveJavaTypeFactory
Gets the RuntimePrimitiveJavaTypeFactory associated with this instance of the runtime.
CoreClasses JavaBase
Gets the CoreClasses associated with this instance of the runtime.
Implementation of global::java.security.PrivilegedAction that invokes a delegate.