IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
RuntimeJavaField.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-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.Diagnostics;
26
27using IKVM.Attributes;
28
29using System.Threading;
30
31#if IMPORTER || EXPORTER
32using IKVM.Reflection;
34
35using Type = IKVM.Reflection.Type;
36#else
37using System.Reflection;
38using System.Reflection.Emit;
39#endif
40
41namespace IKVM.Runtime
42{
43
45 {
46
47#if !IMPORTER && !FIRST_PASS && !EXPORTER
48 volatile java.lang.reflect.Field reflectionField;
49#endif
50 FieldInfo field;
51 RuntimeJavaType fieldType;
52
63 internal RuntimeJavaField(RuntimeJavaType declaringType, RuntimeJavaType fieldType, string name, string sig, Modifiers modifiers, FieldInfo field, MemberFlags flags) :
64 base(declaringType, name, sig, modifiers, flags)
65 {
66 if (name == null)
67 throw new ArgumentNullException();
68 if (sig == null)
69 throw new ArgumentNullException();
70
71 this.fieldType = fieldType;
72 this.field = field;
73
74 UpdateNonPublicTypeInSignatureFlag();
75
76#if IMPORTER
77 if (IsFinal &&
78 DeclaringType.IsPublic &&
79 !DeclaringType.IsInterface &&
80 (IsPublic || (IsProtected && !DeclaringType.IsFinal)) &&
81 !DeclaringType.ClassLoader.StrictFinalFieldSemantics &&
82 DeclaringType.IsDynamic &&
83 this is not RuntimeConstantJavaField &&
85 {
87 }
88#endif
89 }
90
100 internal RuntimeJavaField(RuntimeJavaType declaringType, RuntimeJavaType fieldType, string name, string sig, ExModifiers modifiers, FieldInfo field) :
101 this(declaringType, fieldType, name, sig, modifiers.Modifiers, field, (modifiers.IsInternal ? MemberFlags.InternalAccess : MemberFlags.None))
102 {
103
104 }
105
106 void UpdateNonPublicTypeInSignatureFlag()
107 {
108 if ((IsPublic || IsProtected) && fieldType != null && !IsAccessStub)
109 {
110 if (!fieldType.IsPublic && !fieldType.IsUnloadable)
111 {
113 }
114 }
115 }
116
121 internal FieldInfo GetField()
122 {
123 AssertLinked();
124 return field;
125 }
126
130 [Conditional("DEBUG")]
131 internal void AssertLinked()
132 {
133 if (fieldType == null)
134 throw new InternalException($"Field is not linked: {DeclaringType.Name}::{Name} ({Signature})");
135
136 Debug.Assert(fieldType != null, this.DeclaringType.Name + "::" + this.Name + " (" + this.Signature + ")");
137 }
138
139#if !IMPORTER && !EXPORTER
140
146 internal static RuntimeJavaField FromField(java.lang.reflect.Field field)
147 {
148#if FIRST_PASS
149 throw new NotImplementedException();
150#else
151 int slot = field._slot();
152 if (slot == -1)
153 {
154 // it's a Field created by Unsafe.objectFieldOffset(Class,String) so we must resolve based on the name
155 foreach (var fw in RuntimeJavaType.FromClass(field.getDeclaringClass()).GetFields())
156 if (fw.Name == field.getName())
157 return fw;
158 }
159
160 return RuntimeJavaType.FromClass(field.getDeclaringClass()).GetFields()[slot];
161#endif
162 }
163
164 internal object ToField(bool copy)
165 {
166 return ToField(copy, null);
167 }
168
169 internal object ToField(bool copy, int? fieldIndex)
170 {
171#if FIRST_PASS
172 throw new NotImplementedException();
173#else
174 java.lang.reflect.Field field = reflectionField;
175 if (field == null)
176 {
177 const Modifiers ReflectionFieldModifiersMask = Modifiers.Public | Modifiers.Private | Modifiers.Protected | Modifiers.Static | Modifiers.Final | Modifiers.Volatile | Modifiers.Transient | Modifiers.Synthetic | Modifiers.Enum;
178 Link();
179 field = new java.lang.reflect.Field(
180 DeclaringType.ClassObject,
181 Name,
182 FieldTypeWrapper.EnsureLoadable(DeclaringType.ClassLoader).ClassObject,
183 (int)(Modifiers & ReflectionFieldModifiersMask) | (IsInternal ? 0x40000000 : 0),
184 fieldIndex ?? Array.IndexOf(DeclaringType.GetFields(), this),
185 DeclaringType.GetGenericFieldSignature(this),
186 null
187 );
188 }
189
190 lock (this)
191 {
192 if (reflectionField == null)
193 reflectionField = field;
194 else
195 field = reflectionField;
196 }
197
198 if (copy)
199 field = field.copy();
200
201 return field;
202#endif
203 }
204
205#endif
206
212 [System.Security.SecurityCritical]
213 internal static RuntimeJavaField FromCookie(IntPtr cookie)
214 {
215 return (RuntimeJavaField)FromCookieImpl(cookie);
216 }
217
218 internal RuntimeJavaType FieldTypeWrapper
219 {
220 get
221 {
222 AssertLinked();
223 return fieldType;
224 }
225 }
226
227#if EMITTERS
228
233 internal void EmitGet(CodeEmitter il)
234 {
235 AssertLinked();
236 EmitGetImpl(il);
237 }
238
243 protected abstract void EmitGetImpl(CodeEmitter il);
244
249 internal void EmitUnsafeGet(CodeEmitter il)
250 {
251 AssertLinked();
252 EmitUnsafeGetImpl(il);
253 }
254
259 protected virtual void EmitUnsafeGetImpl(CodeEmitter il)
260 {
261 EmitGetImpl(il);
262 }
263
268 internal void EmitUnsafeVolatileGet(CodeEmitter il)
269 {
270 AssertLinked();
271 EmitUnsafeVolatileGetImpl(il);
272 }
273
278 protected virtual void EmitUnsafeVolatileGetImpl(CodeEmitter il)
279 {
280 throw new NotSupportedException();
281 }
282
287 internal void EmitSet(CodeEmitter il)
288 {
289 AssertLinked();
290 EmitSetImpl(il);
291 }
292
297 protected abstract void EmitSetImpl(CodeEmitter il);
298
303 internal void EmitUnsafeSet(CodeEmitter il)
304 {
305 AssertLinked();
306 EmitSetImpl(il);
307 }
308
313 protected virtual void EmitUnsafeSetImpl(CodeEmitter il)
314 {
315 EmitSetImpl(il);
316 }
317
322 internal void EmitUnsafeVolatileSet(CodeEmitter il)
323 {
324 AssertLinked();
325 EmitUnsafeVolatileSetImpl(il);
326 }
327
332 protected virtual void EmitUnsafeVolatileSetImpl(CodeEmitter il)
333 {
334 throw new NotSupportedException();
335 }
336
342 internal void EmitUnsafeCompareAndSwap(CodeEmitter il)
343 {
344 AssertLinked();
345 EmitUnsafeCompareAndSwapImpl(il);
346 }
347
353 protected virtual void EmitUnsafeCompareAndSwapImpl(CodeEmitter il)
354 {
355 throw new NotSupportedException();
356 }
357
358#endif
359
360#if IMPORTER
361
362 internal bool IsLinked
363 {
364 get { return fieldType != null; }
365 }
366
367#endif
368
369 internal void Link()
370 {
371 Link(LoadMode.Link);
372 }
373
374 internal void Link(LoadMode mode)
375 {
376 lock (this)
377 if (fieldType != null)
378 return;
379
380 var fld = DeclaringType.ClassLoader.FieldTypeWrapperFromSig(Signature, mode);
381
382 lock (this)
383 {
384 try
385 {
386 // critical code in the finally block to avoid Thread.Abort interrupting the thread
387 }
388 finally
389 {
390 if (fieldType == null)
391 {
392 fieldType = fld;
393 UpdateNonPublicTypeInSignatureFlag();
394
395 try
396 {
397 field = this.DeclaringType.LinkField(this);
398 }
399 catch
400 {
401 // HACK if linking fails, we unlink to make sure
402 // that the next link attempt will fail again
403 fieldType = null;
404 throw;
405 }
406 }
407 }
408 }
409 }
410
411 internal bool IsVolatile
412 {
413 get
414 {
415 return (Modifiers & Modifiers.Volatile) != 0;
416 }
417 }
418
419 internal bool IsSerialVersionUID
420 {
421 get
422 {
423 // a serialVersionUID field must be static and final to be recognized (see ObjectStreamClass.getDeclaredSUID())
424 return (Modifiers & (Modifiers.Static | Modifiers.Final)) == (Modifiers.Static | Modifiers.Final)
425 && Name == "serialVersionUID"
426 && (FieldTypeWrapper == DeclaringType.Context.PrimitiveJavaTypeFactory.LONG
427 || FieldTypeWrapper == DeclaringType.Context.PrimitiveJavaTypeFactory.INT
428 || FieldTypeWrapper == DeclaringType.Context.PrimitiveJavaTypeFactory.CHAR
429 || FieldTypeWrapper == DeclaringType.Context.PrimitiveJavaTypeFactory.SHORT
430 || FieldTypeWrapper == DeclaringType.Context.PrimitiveJavaTypeFactory.BYTE);
431 }
432 }
433
434 internal static RuntimeJavaField Create(RuntimeJavaType declaringType, RuntimeJavaType fieldType, FieldInfo fi, string name, string sig, ExModifiers modifiers)
435 {
436 // volatile long & double field accesses must be made atomic
437 if ((modifiers.Modifiers & Modifiers.Volatile) != 0 && (sig == "J" || sig == "D"))
438 return new RuntimeVolatileLongDoubleJavaField(declaringType, fieldType, fi, name, sig, modifiers);
439
440 return new RuntimeSimpleJavaField(declaringType, fieldType, fi, name, sig, modifiers);
441 }
442
443#if !IMPORTER && !EXPORTER
444 internal virtual void ResolveField()
445 {
446 var fb = field as FieldBuilder;
447 if (fb != null)
448 {
449#if NETFRAMEWORK
450 field = fb.DeclaringType.Module.ResolveField(fb.GetToken().Token);
451#else
452 BindingFlags flags = BindingFlags.DeclaredOnly;
453 flags |= fb.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
454 flags |= fb.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
455 field = DeclaringType.TypeAsTBD.GetField(fb.Name, flags);
456#endif
457 }
458 }
459
460#if !FIRST_PASS
461
467 internal abstract object GetValue(object obj);
468
474 internal abstract void SetValue(object obj, object value);
475
476 Delegate unsafeGetValueDelegate;
477 Delegate unsafeSetValueDelegate;
478 Delegate unsafeVolatileGetDelegate;
479 Delegate unsafeVolatileSetDelegate;
480 Delegate unsafeCompareExchangeDelegate;
481
487 internal virtual TField UnsafeGetValue<TField>(object obj)
488 {
489 return ((Func<object, TField>)GetUnsafeGetDelegate())(obj);
490 }
491
496 Delegate GetUnsafeGetDelegate()
497 {
498 if (unsafeGetValueDelegate == null)
499 Interlocked.CompareExchange(ref unsafeGetValueDelegate, CreateUnsafeGetDelegate(), null);
500
501 return unsafeGetValueDelegate;
502 }
503
508 Delegate CreateUnsafeGetDelegate()
509 {
510 DeclaringType.Finish();
511 FieldTypeWrapper.Finish();
512 ResolveField();
513
514 var ft = FieldTypeWrapper.IsPrimitive ? FieldTypeWrapper.TypeAsSignatureType : typeof(object);
515 var dm = DynamicMethodUtil.Create($"__<UnsafeGet>__{DeclaringType.Name.Replace(".", "_")}__{Name}", DeclaringType.TypeAsTBD, true, ft, new[] { typeof(object) });
516 var il = JVM.Context.CodeEmitterFactory.Create(dm);
517
518 if (IsStatic == false)
519 il.Emit(OpCodes.Ldarg_0);
520
521 EmitUnsafeGet(il);
522
523 il.Emit(OpCodes.Ret);
524 il.DoEmit();
525 return dm.CreateDelegate(typeof(Func<,>).MakeGenericType(typeof(object), ft));
526 }
527
534 internal virtual void UnsafeSetValue<TField>(object obj, TField value)
535 {
536 ((Action<object, TField>)GetUnsafeSetDelegate())(obj, value);
537 }
538
543 Delegate GetUnsafeSetDelegate()
544 {
545 if (unsafeSetValueDelegate == null)
546 Interlocked.CompareExchange(ref unsafeSetValueDelegate, CreateUnsafeSetDelegate(), null);
547
548 return unsafeSetValueDelegate;
549 }
550
555 Delegate CreateUnsafeSetDelegate()
556 {
557 DeclaringType.Finish();
558 FieldTypeWrapper.Finish();
559 ResolveField();
560
561 var ft = FieldTypeWrapper.IsPrimitive ? FieldTypeWrapper.TypeAsSignatureType : typeof(object);
562 var dm = DynamicMethodUtil.Create($"__<UnsafeSet>__{DeclaringType.Name.Replace(".", "_")}__{Name}", DeclaringType.TypeAsTBD, true, typeof(void), new[] { typeof(object), ft });
563 var il = JVM.Context.CodeEmitterFactory.Create(dm);
564
565 if (IsStatic == false)
566 il.Emit(OpCodes.Ldarg_0);
567
568 il.Emit(OpCodes.Ldarg_1);
569 EmitUnsafeSet(il);
570
571 il.Emit(OpCodes.Ret);
572 il.DoEmit();
573 return dm.CreateDelegate(typeof(Action<,>).MakeGenericType(typeof(object), ft));
574 }
575
582 internal virtual TField UnsafeVolatileGet<TField>(object obj)
583 {
584 return ((Func<object, TField>)GetUnsafeVolatileGetDelegate())(obj);
585 }
586
591 Delegate GetUnsafeVolatileGetDelegate()
592 {
593 if (unsafeVolatileGetDelegate == null)
594 Interlocked.CompareExchange(ref unsafeVolatileGetDelegate, CreateUnsafeVolatileGetDelegate(), null);
595
596 return unsafeVolatileGetDelegate;
597 }
598
603 Delegate CreateUnsafeVolatileGetDelegate()
604 {
605 ResolveField();
606 var ft = FieldTypeWrapper.IsPrimitive ? FieldTypeWrapper.TypeAsSignatureType : typeof(object);
607 var dm = new DynamicMethod($"__<UnsafeVolatileGet>__{DeclaringType.Name.Replace(".", "_")}__{Name}", ft, new[] { typeof(object) }, DeclaringType.TypeAsTBD.Module, true);
608 var il = JVM.Context.CodeEmitterFactory.Create(dm);
609
610 if (IsStatic == false)
611 il.Emit(OpCodes.Ldarg_0);
612
613 EmitUnsafeVolatileGet(il);
614
615 il.Emit(OpCodes.Ret);
616 il.DoEmit();
617 return dm.CreateDelegate(typeof(Func<,>).MakeGenericType(typeof(object), ft));
618 }
619
627 internal virtual void UnsafeVolatileSet<TField>(object obj, TField value)
628 {
629 ((Action<object, TField>)GetUnsafeVolatileSetDelegate())(obj, value);
630 }
631
636 Delegate GetUnsafeVolatileSetDelegate()
637 {
638 if (unsafeVolatileSetDelegate == null)
639 Interlocked.CompareExchange(ref unsafeVolatileSetDelegate, CreateUnsafeVolatileSetDelegate(), null);
640
641 return unsafeVolatileSetDelegate;
642 }
643
648 Delegate CreateUnsafeVolatileSetDelegate()
649 {
650 ResolveField();
651 var ft = FieldTypeWrapper.IsPrimitive ? FieldTypeWrapper.TypeAsSignatureType : typeof(object);
652 var dm = DynamicMethodUtil.Create($"__<UnsafeVolatileSet>__{DeclaringType.Name.Replace(".", "_")}__{Name}", DeclaringType.TypeAsTBD, true, typeof(void), new[] { typeof(object), ft });
653 var il = JVM.Context.CodeEmitterFactory.Create(dm);
654
655 if (IsStatic == false)
656 il.Emit(OpCodes.Ldarg_0);
657
658 il.Emit(OpCodes.Ldarg_1);
659 EmitUnsafeVolatileSet(il);
660
661 il.Emit(OpCodes.Ret);
662 il.DoEmit();
663 return dm.CreateDelegate(typeof(Action<,>).MakeGenericType(typeof(object), ft));
664 }
665
674 internal virtual bool UnsafeCompareAndSwap<TField>(object obj, TField expected, TField value)
675 {
676 return ((Func<object, TField, TField, bool>)GetUnsafeCompareAndSwapDelegate())(obj, expected, value);
677 }
678
679
684 Delegate GetUnsafeCompareAndSwapDelegate()
685 {
686 if (unsafeCompareExchangeDelegate == null)
687 Interlocked.CompareExchange(ref unsafeCompareExchangeDelegate, CreateUnsafeCompareAndSwapDelegate(), null);
688
689 return unsafeCompareExchangeDelegate;
690 }
691
696 Delegate CreateUnsafeCompareAndSwapDelegate()
697 {
698 ResolveField();
699 var ft = FieldTypeWrapper.IsPrimitive ? FieldTypeWrapper.TypeAsSignatureType : typeof(object);
700 var dm = DynamicMethodUtil.Create($"__<UnsafeCompareAndSwap>__{DeclaringType.Name.Replace(".", "_")}__{Name}", DeclaringType.TypeAsTBD, true, typeof(bool), new[] { typeof(object), ft, ft });
701 var il = JVM.Context.CodeEmitterFactory.Create(dm);
702
703 if (IsStatic == false)
704 il.Emit(OpCodes.Ldarg_0);
705
706 il.Emit(OpCodes.Ldarg_1);
707 il.Emit(OpCodes.Ldarg_2);
708 EmitUnsafeCompareAndSwap(il);
709
710 il.Emit(OpCodes.Ret);
711 il.DoEmit();
712 return dm.CreateDelegate(typeof(Func<,,,>).MakeGenericType(typeof(object), ft, ft, typeof(bool)));
713 }
714
715#endif
716
717#endif
718
719 }
720
721}
System.Threading.Interlocked Interlocked
IKVM.Reflection.Type Type
IKVM.Reflection.FieldInfo FieldInfo
global::java.lang.invoke.LambdaForm.Name Name
CodeEmitter Create(MethodBuilder mb)
Creates a new instance.
Provides utilities for working with dynamic methods.
Represents an internal error that occurred within IKVM.
Main state of the running JVM.
Represents a .NET property defined in Java with the ikvm.lang.Property annotation.
CodeEmitterFactory CodeEmitterFactory
Gets the CodeEmitterFactory associated with this instance of the runtime.
RuntimePrimitiveJavaTypeFactory PrimitiveJavaTypeFactory
Gets the RuntimePrimitiveJavaTypeFactory associated with this instance of the runtime.
Field wrapper implementation for standard fields.
Field wrapper for a field of type 'volatile long' or 'volatile double'.
MemberFlags
Describes various options applied to a member.