bool LoadFieldValue(string fldName, CilType fldType, CilType fldClass, bool isStatic, bool isVolatile) { if (isStatic && fldClass.HasGenericParameters) { fldClass = LoadStaticData(fldClass); isStatic = false; } byte op; if (!isStatic) { if (method.IsConstructor && LoadFieldInConstructor(fldName, fldType, fldClass)) { return(true); } PopObjectAndLoadFromSpan(fldClass); op = 0xB4; // getfield } else { op = 0xB2; // getstatic } code.NewInstruction(op, fldClass.AsWritableClass, new JavaFieldRef(fldName, fldType)); if (fldType is BoxedType boxedType) { boxedType.GetValue(code, isVolatile); fldType = boxedType.UnboxedType; if (fldType.IsReference) { if (fldType.IsGenericParameter && fldType.IsArray) { fldType = CodeArrays.GenericArrayType; } else if (!fldType.Equals(JavaType.ObjectType)) { code.NewInstruction(0xC0 /* checkcast */, fldType.AsWritableClass, null); } } } else if (fldType.IsGenericParameter) { var newType = GenericUtil.CastMaybeGeneric(fldType, false, code); fldType = (newType != fldType) ? newType : CilType.From(JavaType.ObjectType); } stackMap.PushStack(fldType); return(true); }
bool LoadFieldAddress(string fldName, CilType fldType, CilType fldClass, bool isStatic) { if (!(fldType is BoxedType)) { if (!fldType.IsValueClass) { throw CilMain.Where.Exception($"cannot load address of unboxed field '{fldName}'"); } } if (isStatic && fldClass.HasGenericParameters) { fldClass = LoadStaticData(fldClass); isStatic = false; } byte op; if (!isStatic) { PopObjectAndLoadFromSpan(fldClass); op = 0xB4; // getfield } else { op = 0xB2; // getstatic } code.NewInstruction(op, fldClass.AsWritableClass, new JavaFieldRef(fldName, fldType)); if (fldType is ThreadBoxedType tlsType) { tlsType.GetInnerObject(code); } if (fldType.IsGenericParameter) { fldType = GenericUtil.CastMaybeGeneric(fldType, true, code); } stackMap.PushStack(fldType); return(true); }
public static void Indirection(JavaCode code, Code cilOp) { var(name, opcodeType) = IndirectOpCodeToNameAndType(cilOp); bool isRef = opcodeType.Equals(JavaType.ObjectType); bool isLoad; if (cilOp >= Code.Ldind_I1 && cilOp <= Code.Ldind_Ref) { isLoad = true; } else { isLoad = false; var valueType = code.StackMap.PopStack(CilMain.Where); if (valueType.IsReference != isRef) { throw new InvalidProgramException(); } } var stackTop = (CilType)code.StackMap.PopStack(CilMain.Where); if (stackTop.IsGenericParameter) { if (isLoad) { var resultType = GenericUtil.CastMaybeGeneric(stackTop, false, code); if (resultType == stackTop && (!stackTop.Equals(JavaType.ObjectType))) { code.NewInstruction(0xC0 /* checkcast */, stackTop.AsWritableClass, null); resultType = stackTop; } code.StackMap.PushStack(resultType); } else { code.NewInstruction(0x5F /* swap */, null, null); GenericUtil.ValueCopy(stackTop, code); } return; } // // non-generic object reference // var boxedType = stackTop as BoxedType; if (boxedType == null || boxedType.IsBoxedReference != isRef) { if (CodeSpan.LoadStore(isLoad, stackTop, opcodeType, null, code)) { return; } if (object.ReferenceEquals(stackTop, CodeArrays.GenericArrayType)) { // a byref parameter T[] gets translated to java.lang.Object, // so we have to explicitly cast it to system.Reference boxedType = new BoxedType(stackTop, false); code.NewInstruction(0x5F /* swap */, null, null); code.NewInstruction(0xC0 /* checkcast */, boxedType.AsWritableClass, null); code.NewInstruction(0x5F /* swap */, null, null); } else { throw new ArgumentException($"incompatible type '{stackTop}'"); } } var unboxedType = boxedType.UnboxedType; var unboxedTypeCode = unboxedType.IsReference ? 0 : unboxedType.PrimitiveType; JavaMethodRef method; if (CompareIndirectTypes(unboxedTypeCode, opcodeType.PrimitiveType)) { // indirect access to a primitive or reference type, with a // reference type that represents the boxed form of the same type. if (isLoad) { boxedType.GetValue(code); if (unboxedType.IsReference) { // if we know the type of indirected value, cast to it if (!unboxedType.Equals(JavaType.ObjectType)) { code.NewInstruction(0xC0 /* checkcast */, unboxedType.AsWritableClass, null); } } else { unboxedType = CilType.From(opcodeType); } code.StackMap.PushStack(unboxedType); } else { // if we are storing a real array into a boxed reference of // e.g., system.Array, then we have to create an array proxy CodeArrays.MaybeGetProxy(CodeArrays.GenericArrayType, unboxedType, code); boxedType.SetValueOV(code); } return; } // indirect access to a primitive value from a reference type that // represents some other a primitive value; for example ldind.r4 // from a system.Int32. we call the "CodeNumber.Indirection methods" // helpers, defined in all baselib primitives, to assist. if (opcodeType.IsIntLike) { opcodeType = JavaType.IntegerType; } if (isLoad) { method = new JavaMethodRef("Get_" + name, opcodeType); code.StackMap.PushStack(CilType.From(opcodeType)); } else { method = new JavaMethodRef("Set_" + name, JavaType.VoidType, opcodeType); } code.NewInstruction(0xB6 /* invokevirtual */, boxedType, method); }