45 readonly RuntimeJavaType _host;
46 readonly RuntimeJavaType _type;
49 readonly ClassFile.Method _classFileMethod;
51 readonly RuntimeJavaType _thisType;
53 List<string> _errorMessages;
54 readonly Dictionary<int, RuntimeJavaType> _newTypes =
new Dictionary<int, RuntimeJavaType>();
55 readonly Dictionary<int, RuntimeJavaType> _faultTypes =
new Dictionary<int, RuntimeJavaType>();
63 _context = context ??
throw new ArgumentNullException(nameof(context));
86 if (classFileMethod.VerifyError !=
null)
92 _classFile = classFile;
93 _classFileMethod = classFileMethod;
94 _classLoader = classLoader;
100 for (int i = 0; i < classFileMethod.ExceptionTable.Length; i++)
102 int start = classFileMethod.ExceptionTable[i].startIndex;
103 int end = classFileMethod.ExceptionTable[i].endIndex;
104 int handler = classFileMethod.ExceptionTable[i].handlerIndex;
105 if (start >= end || start == -1 || end == -1 || handler <= 0)
106 throw new IndexOutOfRangeException();
109 catch (IndexOutOfRangeException)
112 throw new ClassFormatError($
"Illegal exception table (class: {classFile.Name}, method: {classFileMethod.Name}, signature: {classFileMethod.Signature}");
116 _state[0] =
new InstructionState(context, classFileMethod.MaxLocals, classFileMethod.MaxStack);
117 int firstNonArgLocalIndex = 0;
119 if (classFileMethod.IsStatic ==
false)
121 _thisType = RuntimeVerifierJavaType.MakeThis(type);
124 if (classFileMethod.IsConstructor)
127 _state[0].SetUnitializedThis(
true);
131 _state[0].SetLocalType(firstNonArgLocalIndex++, _thisType, -1);
140 var argTypes = method !=
null ? method.GetParameters() : [];
141 for (
int i = 0; i < argTypes.Length; i++)
143 var argType = argTypes[i];
144 if (argType.IsIntOnStackPrimitive)
147 _state[0].SetLocalType(firstNonArgLocalIndex++, argType, -1);
148 if (argType.IsWidePrimitive)
149 firstNonArgLocalIndex++;
154 PatchLoadConstants();
160 void PatchLoadConstants()
162 var code = _classFileMethod.Instructions;
163 for (
int i = 0; i < code.Length; i++)
165 if (_state[i]._initialized)
167 switch (code[i].NormalizedOpCode)
170 switch (GetConstantPoolConstantType(code[i].Arg1))
172 case ClassFile.ConstantType.Double:
173 case ClassFile.ConstantType.Float:
174 case ClassFile.ConstantType.Integer:
175 case ClassFile.ConstantType.Long:
176 case ClassFile.ConstantType.String:
177 case ClassFile.ConstantType.LiveObject:
188 internal CodeInfo GetCodeInfoAndErrors(UntangledExceptionTable exceptions, out List<string> errors)
190 var codeInfo =
new CodeInfo(_context, _state);
192 OptimizationPass(codeInfo, _classFile, _classFileMethod, exceptions, _type, _classLoader);
193 PatchHardErrorsAndDynamicMemberAccess(_type, _method);
194 errors = _errorMessages;
196 if (AnalyzePotentialFaultBlocks(codeInfo, _classFileMethod, exceptions))
199 ConvertFinallyBlocks(codeInfo, _classFileMethod, exceptions);
203 void AnalyzeTypeFlow()
205 var s =
new InstructionState(_context, _classFileMethod.MaxLocals, _classFileMethod.MaxStack);
207 var instructions = _classFileMethod.Instructions;
209 while (done ==
false)
213 for (
int i = 0; i < instructions.Length; i++)
215 if (_state[i]._initialized && _state[i]._changed)
221 _state[i]._changed =
false;
224 for (
int j = 0; j < _classFileMethod.ExceptionTable.Length; j++)
225 if (_classFileMethod.ExceptionTable[j].startIndex <= i && i < _classFileMethod.ExceptionTable[j].endIndex)
226 MergeExceptionHandler(j,
ref _state[i]);
229 _state[i].CopyTo(
ref s);
231 var inst = instructions[i];
232 switch (inst.NormalizedOpCode)
236 var type = s.GetLocalType(inst.NormalizedArg1);
237 if (type == _context.VerifierJavaTypeFactory.Invalid || type.IsPrimitive)
238 throw new VerifyError(
"Object reference expected");
245 if (RuntimeVerifierJavaType.IsFaultBlockException(s.PeekType()))
247 s.SetLocalType(inst.NormalizedArg1, s.PopFaultBlockException(), i);
252 var type = s.PopType();
253 if (type.IsPrimitive)
254 throw new VerifyError(
"Object reference expected");
256 s.SetLocalType(inst.NormalizedArg1, type, i);
260 s.PushType(_context.VerifierJavaTypeFactory.Null);
265 var type = s.PopArrayType();
266 if (type == _context.VerifierJavaTypeFactory.Null)
270 s.PushType(_context.VerifierJavaTypeFactory.Null);
272 else if (type.IsUnloadable)
274 s.PushType(_context.VerifierJavaTypeFactory.Unloadable);
278 type = type.ElementTypeWrapper;
279 if (type.IsPrimitive)
296 var type = s.PopArrayType();
297 if (!RuntimeVerifierJavaType.IsNullOrUnloadable(type) && type != _context.MethodAnalyzerFactory.ByteArrayType && type != _context.MethodAnalyzerFactory.BooleanArrayType)
308 var type = s.PopArrayType();
309 if (!RuntimeVerifierJavaType.IsNullOrUnloadable(type) && type != _context.MethodAnalyzerFactory.ByteArrayType && type != _context.MethodAnalyzerFactory.BooleanArrayType)
316 s.PopObjectType(_context.MethodAnalyzerFactory.CharArrayType);
322 s.PopObjectType(_context.MethodAnalyzerFactory.CharArrayType);
326 s.PopObjectType(_context.MethodAnalyzerFactory.ShortArrayType);
332 s.PopObjectType(_context.MethodAnalyzerFactory.ShortArrayType);
336 s.PopObjectType(_context.MethodAnalyzerFactory.IntArrayType);
342 s.PopObjectType(_context.MethodAnalyzerFactory.IntArrayType);
346 s.PopObjectType(_context.MethodAnalyzerFactory.LongArrayType);
352 s.PopObjectType(_context.MethodAnalyzerFactory.LongArrayType);
356 s.PopObjectType(_context.MethodAnalyzerFactory.DoubleArrayType);
362 s.PopObjectType(_context.MethodAnalyzerFactory.DoubleArrayType);
366 s.PopObjectType(_context.MethodAnalyzerFactory.FloatArrayType);
372 s.PopObjectType(_context.MethodAnalyzerFactory.FloatArrayType);
414 switch (GetFieldref(inst.Arg1).Signature[0])
436 throw new InvalidOperationException();
441 var cpi = GetFieldref(inst.Arg1);
442 if (cpi.GetField() !=
null && cpi.GetField().FieldTypeWrapper.IsUnloadable)
443 s.PushType(cpi.GetField().FieldTypeWrapper);
445 s.PushType(cpi.GetFieldType());
453 switch (GetFieldref(inst.Arg1).Signature[0])
473 if (s.PopAnyType() != _context.VerifierJavaTypeFactory.Null)
477 throw new InvalidOperationException();
482 s.PopType(GetFieldref(inst.Arg1).GetFieldType());
488 s.PopObjectType(GetFieldref(inst.Arg1).GetClassType());
490 var cpi = GetFieldref(inst.Arg1);
491 if (cpi.GetField() !=
null && cpi.GetField().FieldTypeWrapper.IsUnloadable)
492 s.PushType(cpi.GetField().FieldTypeWrapper);
494 s.PushType(cpi.GetFieldType());
500 s.PopType(GetFieldref(inst.Arg1).GetFieldType());
503 if (s.PeekType() == _context.VerifierJavaTypeFactory.UninitializedThis && _type.IsAssignableTo(GetFieldref(inst.Arg1).GetClassType()))
506 s.PopObjectType(GetFieldref(inst.Arg1).GetClassType());
512 switch (GetConstantPoolConstantType(inst.Arg1))
514 case ClassFile.ConstantType.Double:
517 case ClassFile.ConstantType.Float:
520 case ClassFile.ConstantType.Integer:
523 case ClassFile.ConstantType.Long:
526 case ClassFile.ConstantType.String:
527 s.PushType(_context.JavaBase.TypeOfJavaLangString);
529 case ClassFile.ConstantType.LiveObject:
530 s.PushType(_context.JavaBase.TypeOfJavaLangObject);
532 case ClassFile.ConstantType.Class:
533 if (_classFile.MajorVersion < 49)
534 throw new VerifyError(
"Illegal type in constant pool");
536 s.PushType(_context.JavaBase.TypeOfJavaLangClass);
538 case ClassFile.ConstantType.MethodHandle:
539 s.PushType(_context.JavaBase.TypeOfJavaLangInvokeMethodHandle);
541 case ClassFile.ConstantType.MethodType:
542 s.PushType(_context.JavaBase.TypeOfJavaLangInvokeMethodType);
547 throw new InvalidOperationException();
567 var cpi = GetMethodref(inst.Arg1);
568 var retType = cpi.GetRetType();
573 if (cpi.GetMethod() !=
null && cpi.GetMethod().IsIntrinsic && cpi.Class ==
"sun.misc.Unsafe" && cpi.Name ==
"getObjectVolatile" &&
Intrinsics.IsSupportedArrayTypeForUnsafeOperation(s.GetStackSlot(1)))
574 retType = s.GetStackSlot(1).ElementTypeWrapper;
576 s.MultiPopAnyType(cpi.GetArgTypes().Length);
580 var type = s.PopType();
581 if (ReferenceEquals(cpi.Name, StringConstants.INIT))
585 if (type == _context.VerifierJavaTypeFactory.UninitializedThis)
587 if (s.GetLocalTypeEx(0) == type)
588 s.SetLocalType(0, _thisType, i);
590 s.MarkInitialized(type, _type, i);
591 s.SetUnitializedThis(
false);
593 else if (RuntimeVerifierJavaType.IsNew(type))
595 s.MarkInitialized(type, ((RuntimeVerifierJavaType)type).UnderlyingType, i);
604 if (retType != _context.PrimitiveJavaTypeFactory.VOID)
606 if (cpi.GetMethod() !=
null && cpi.GetMethod().ReturnType.IsUnloadable)
608 s.PushType(cpi.GetMethod().ReturnType);
610 else if (retType == _context.PrimitiveJavaTypeFactory.DOUBLE)
612 s.PushExtendedDouble();
614 else if (retType == _context.PrimitiveJavaTypeFactory.FLOAT)
616 s.PushExtendedFloat();
628 var cpi = GetInvokeDynamic(inst.Arg1);
629 s.MultiPopAnyType(cpi.GetArgTypes().Length);
631 var retType = cpi.GetRetType();
632 if (retType != _context.PrimitiveJavaTypeFactory.VOID)
634 if (retType == _context.PrimitiveJavaTypeFactory.DOUBLE)
636 s.PushExtendedDouble();
638 else if (retType == _context.PrimitiveJavaTypeFactory.FLOAT)
640 s.PushExtendedFloat();
654 s.SetLocalInt(inst.NormalizedArg1, i);
657 s.GetLocalInt(inst.NormalizedArg1);
704 s.PushExtendedFloat();
715 s.PushExtendedFloat();
719 s.PushExtendedDouble();
731 s.PushExtendedDouble();
736 if (!_newTypes.TryGetValue(i, out var type))
738 type = GetConstantPoolClassType(inst.Arg1);
740 throw new VerifyError(
"Illegal use of array type");
742 type = RuntimeVerifierJavaType.MakeNew(type, i);
752 throw new VerifyError(
"Illegal dimension argument");
754 for (
int j = 0; j < inst.Arg2; j++)
757 var type = GetConstantPoolClassType(inst.Arg1);
758 if (type.ArrayRank < inst.Arg2)
759 throw new VerifyError(
"Illegal dimension argument");
767 var type = GetConstantPoolClassType(inst.Arg1);
768 if (type.IsUnloadable)
769 s.PushType(
new RuntimeUnloadableJavaType(_context,
"[" + type.SigName));
771 s.PushType(type.MakeArrayType(1));
780 s.PushType(_context.MethodAnalyzerFactory.BooleanArrayType);
783 s.PushType(_context.MethodAnalyzerFactory.CharArrayType);
786 s.PushType(_context.MethodAnalyzerFactory.FloatArrayType);
789 s.PushType(_context.MethodAnalyzerFactory.DoubleArrayType);
792 s.PushType(_context.MethodAnalyzerFactory.ByteArrayType);
795 s.PushType(_context.MethodAnalyzerFactory.ShortArrayType);
798 s.PushType(_context.MethodAnalyzerFactory.IntArrayType);
801 s.PushType(_context.MethodAnalyzerFactory.LongArrayType);
809 var t1 = s.PopType();
810 var t2 = s.PopType();
824 var t = s.PopAnyType();
825 if (t.IsWidePrimitive || t == _context.VerifierJavaTypeFactory.ExtendedDouble)
832 var t2 = s.PopType();
842 var value1 = s.PopType();
843 var value2 = s.PopType();
851 var value1 = s.PopAnyType();
852 if (value1.IsWidePrimitive || value1 == _context.VerifierJavaTypeFactory.ExtendedDouble)
854 var value2 = s.PopType();
861 var value2 = s.PopType();
862 var value3 = s.PopType();
873 var value1 = s.PopType();
874 var value2 = s.PopAnyType();
875 if (value2.IsWidePrimitive || value2 == _context.VerifierJavaTypeFactory.ExtendedDouble)
883 var value3 = s.PopType();
893 var value1 = s.PopAnyType();
894 if (value1.IsWidePrimitive || value1 == _context.VerifierJavaTypeFactory.ExtendedDouble)
896 var value2 = s.PopAnyType();
897 if (value2.IsWidePrimitive || value2 == _context.VerifierJavaTypeFactory.ExtendedDouble)
907 var value3 = s.PopType();
916 var value2 = s.PopType();
917 var value3 = s.PopAnyType();
918 if (value3.IsWidePrimitive || value3 == _context.VerifierJavaTypeFactory.ExtendedDouble)
930 var value4 = s.PopType();
946 var type = s.PopAnyType();
947 if (!type.IsWidePrimitive && type != _context.VerifierJavaTypeFactory.ExtendedDouble)
962 if (_method.ReturnType != _context.PrimitiveJavaTypeFactory.VOID)
963 throw new VerifyError(
"Wrong return type in function");
966 s.CheckUninitializedThis();
970 s.PopObjectType(_method.ReturnType);
975 if (!_method.ReturnType.IsIntOnStackPrimitive)
976 throw new VerifyError(
"Wrong return type in function");
982 if (_method.ReturnType != _context.PrimitiveJavaTypeFactory.LONG)
983 throw new VerifyError(
"Wrong return type in function");
988 if (_method.ReturnType != _context.PrimitiveJavaTypeFactory.FLOAT)
989 throw new VerifyError(
"Wrong return type in function");
994 if (_method.ReturnType != _context.PrimitiveJavaTypeFactory.DOUBLE)
995 throw new VerifyError(
"Wrong return type in function");
999 s.GetLocalFloat(inst.NormalizedArg1);
1004 s.SetLocalFloat(inst.NormalizedArg1, i);
1007 s.GetLocalDouble(inst.NormalizedArg1);
1012 s.SetLocalDouble(inst.NormalizedArg1, i);
1015 s.GetLocalLong(inst.NormalizedArg1);
1020 s.SetLocalLong(inst.NormalizedArg1, i);
1054 s.PushType(GetConstantPoolClassType(inst.Arg1));
1061 s.GetLocalInt(inst.Arg1);
1064 if (RuntimeVerifierJavaType.IsFaultBlockException(s.PeekType()))
1065 s.PopFaultBlockException();
1067 s.PopObjectType(_context.JavaBase.TypeOfjavaLangThrowable);
1134 if (i + 1 == instructions.Length)
1135 throw new VerifyError(
"Falling off the end of the code");
1143 throw new NotImplementedException(inst.NormalizedOpCode.ToString());
1146 if (s.GetStackHeight() > _classFileMethod.MaxStack)
1149 for (
int j = 0; j < _classFileMethod.ExceptionTable.Length; j++)
1150 if (_classFileMethod.ExceptionTable[j].endIndex == i + 1)
1151 MergeExceptionHandler(j,
ref s);
1155 switch (ByteCodeMetaData.GetFlowControl(inst.NormalizedOpCode))
1158 for (
int j = 0; j < inst.SwitchEntryCount; j++)
1159 _state[inst.GetSwitchTargetIndex(j)] += s;
1161 _state[inst.DefaultTarget] += s;
1165 _state[inst.TargetIndex] += s;
1168 _state[inst.TargetIndex] += s;
1177 throw new InvalidOperationException();
1180 catch (IndexOutOfRangeException)
1186 throw new VerifyError(
"Illegal target of jump or branch");
1192 var opcode = instructions[i].NormalizedOpCode.ToString();
1193 if (opcode.StartsWith(
"__"))
1194 opcode = opcode.Substring(2);
1196 throw new VerifyError($
"{x.Message} (class: {_classFile.Name}, method: {_classFileMethod.Name}, signature: {_classFileMethod.Signature}, offset: {instructions[i].PC}, instruction: {opcode})", x);
1203 void MergeExceptionHandler(
int exceptionIndex,
ref InstructionState curr)
1205 var idx = _classFileMethod.ExceptionTable[exceptionIndex].handlerIndex;
1206 var exp = curr.CopyLocals();
1208 var catchType = _classFileMethod.ExceptionTable[exceptionIndex].catchType;
1209 if (catchType.IsNil)
1211 if (_faultTypes.TryGetValue(idx, out var faultType) ==
false)
1213 faultType = RuntimeVerifierJavaType.MakeFaultBlockException(
this, idx);
1214 _faultTypes.Add(idx, faultType);
1217 exp.PushType(faultType);
1223 exp.PushType(GetConstantPoolClassType(catchType));
1230 void VerifyPassTwo()
1232 var instructions = _classFileMethod.Instructions;
1233 for (
int i = 0; i < instructions.Length; i++)
1235 if (_state[i]._initialized)
1239 switch (instructions[i].NormalizedOpCode)
1245 VerifyInvokePassTwo(i);
1248 VerifyInvokeDynamic(i);
1254 var opcode = instructions[i].NormalizedOpCode.ToString();
1255 if (opcode.StartsWith(
"__"))
1256 opcode = opcode.Substring(2);
1258 throw new VerifyError($
"{x.Message} (class: {_classFile.Name}, method: {_classFileMethod.Name}, signature: {_classFileMethod.Signature}, offset: {instructions[i].PC}, instruction: {opcode})", x);
1264 void VerifyInvokePassTwo(
int index)
1266 var stack =
new StackState(_state, index);
1267 var invoke = _classFileMethod.Instructions[index].NormalizedOpCode;
1268 var cpi = GetMethodref(_classFileMethod.Instructions[index].Arg1);
1273 if (invoke ==
NormalizedByteCode.__invokespecial && cpi is ClassFile.ConstantPoolItemInterfaceMethodref)
1275 if (cpi.GetClassType() == _host)
1279 else if (cpi.GetClassType() != _type && Array.IndexOf(_type.Interfaces, cpi.GetClassType()) == -1)
1281 throw new VerifyError(
"Bad invokespecial instruction: interface method reference is in an indirect superinterface.");
1285 else if ((cpi is ClassFile.ConstantPoolItemInterfaceMethodref) != (invoke ==
NormalizedByteCode.__invokeinterface))
1287 throw new VerifyError(
"Illegal constant pool index");
1290 if (invoke !=
NormalizedByteCode.__invokespecial && ReferenceEquals(cpi.Name, StringConstants.INIT))
1291 throw new VerifyError(
"Must call initializers using invokespecial");
1293 if (ReferenceEquals(cpi.Name, StringConstants.CLINIT))
1294 throw new VerifyError(
"Illegal call to internal method");
1296 var args = cpi.GetArgTypes();
1297 for (
int j = args.Length - 1; j >= 0; j--)
1298 stack.PopType(args[j]);
1302 int argcount = args.Length + 1;
1303 for (
int j = 0; j < args.Length; j++)
1304 if (args[j].IsWidePrimitive)
1307 if (_classFileMethod.Instructions[index].Arg2 != argcount)
1313 if (ReferenceEquals(cpi.Name, StringConstants.INIT))
1315 var type = stack.PopType();
1316 var isnew = RuntimeVerifierJavaType.IsNew(type);
1317 if ((isnew && ((RuntimeVerifierJavaType)type).UnderlyingType != cpi.GetClassType()) || (type == _context.VerifierJavaTypeFactory.UninitializedThis && cpi.GetClassType() != _type.BaseTypeWrapper && cpi.GetClassType() != _type) || (!isnew && type != _context.VerifierJavaTypeFactory.UninitializedThis))
1324 throw new VerifyError(
"Call to wrong initialization method");
1331 var refType = stack.PopObjectType();
1332 var targetType = cpi.GetClassType();
1334 if (!RuntimeVerifierJavaType.IsNullOrUnloadable(refType) && !targetType.IsUnloadable && !refType.IsAssignableTo(targetType))
1335 throw new VerifyError(
"Incompatible object argument for function call");
1340 if (RuntimeVerifierJavaType.IsNullOrUnloadable(refType))
1344 else if (refType.IsSubTypeOf(_type))
1348 else if (_host !=
null && refType.IsSubTypeOf(_host))
1354 throw new VerifyError(
"Incompatible target object for invokespecial");
1356 if (targetType.IsUnloadable)
1360 else if (_type.IsSubTypeOf(targetType))
1364 else if (_host !=
null && _host.IsSubTypeOf(targetType))
1370 throw new VerifyError(
"Invokespecial cannot call subclass methods");
1379 var refType = stack.PopObjectType();
1380 var targetType = cpi.GetClassType();
1381 if (!RuntimeVerifierJavaType.IsNullOrUnloadable(refType) && !targetType.IsUnloadable && !refType.IsAssignableTo(targetType) && !targetType.IsInterface)
1382 throw new VerifyError(
"Incompatible object argument for function call");
1388 void VerifyInvokeDynamic(
int index)
1390 var stack =
new StackState(_state, index);
1391 var cpi = GetInvokeDynamic(_classFileMethod.Instructions[index].Arg1);
1392 var args = cpi.GetArgTypes();
1393 for (
int j = args.Length - 1; j >= 0; j--)
1394 stack.PopType(args[j]);
1397 static void OptimizationPass(CodeInfo codeInfo, ClassFile classFile, ClassFile.Method method, UntangledExceptionTable exceptions, RuntimeJavaType wrapper, RuntimeClassLoader classLoader)
1400 if (classLoader.RemoveAsserts)
1404 if (classFile.HasAssertions)
1407 var flags = ComputePartialReachability(codeInfo, method.Instructions, exceptions, 0,
false);
1408 var instructions = method.Instructions;
1409 for (
int i = 0; i < instructions.Length; i++)
1413 instructions[i + 1].TargetIndex > i &&
1416 if (classFile.GetFieldref(instructions[i].Arg1).GetField() is RuntimeConstantJavaField field &&
1417 field.FieldTypeWrapper == classLoader.Context.PrimitiveJavaTypeFactory.BOOLEAN &&
1418 (
bool)field.GetConstantValue())
1421 instructions[i].PatchOpCode(
NormalizedByteCode.__goto, instructions[i + 1].TargetIndex);
1429 void PatchHardErrorsAndDynamicMemberAccess(RuntimeJavaType wrapper, RuntimeJavaMethod mw)
1434 var instructions = _classFileMethod.Instructions;
1435 for (
int i = 0; i < instructions.Length; i++)
1437 if (_state[i]._initialized)
1439 var stack =
new StackState(_state, i);
1441 switch (instructions[i].NormalizedOpCode)
1447 PatchInvoke(wrapper,
ref instructions[i], stack);
1453 PatchFieldAccess(wrapper, mw,
ref instructions[i], stack);
1456 switch (_classFile.GetConstantPoolConstantType(instructions[i].Arg1))
1458 case ClassFile.ConstantType.Class:
1460 var tw = _classFile.GetConstantPoolClassType(instructions[i].Arg1);
1461 if (tw.IsUnloadable)
1462 ConditionalPatchNoClassDefFoundError(
ref instructions[i], tw);
1466 case ClassFile.ConstantType.MethodType:
1468 var cpi = _classFile.GetConstantPoolConstantMethodType(instructions[i].Arg1);
1469 var args = cpi.GetArgTypes();
1470 var tw = cpi.GetRetType();
1471 for (
int j = 0; !tw.IsUnloadable && j < args.Length; j++)
1474 if (tw.IsUnloadable)
1475 ConditionalPatchNoClassDefFoundError(
ref instructions[i], tw);
1479 case ClassFile.ConstantType.MethodHandle:
1480 PatchLdcMethodHandle(
ref instructions[i]);
1486 var tw = _classFile.GetConstantPoolClassType(instructions[i].Arg1);
1487 if (tw.IsUnloadable)
1489 ConditionalPatchNoClassDefFoundError(
ref instructions[i], tw);
1491 else if (!tw.IsAccessibleFrom(wrapper))
1493 SetHardError(wrapper.ClassLoader,
ref instructions[i],
HardError.IllegalAccessError,
"Try to access class {0} from class {1}", tw.Name, wrapper.Name);
1495 else if (tw.IsAbstract)
1497 SetHardError(wrapper.ClassLoader,
ref instructions[i],
HardError.InstantiationError,
"{0}", tw.Name);
1505 var tw = _classFile.GetConstantPoolClassType(instructions[i].Arg1);
1506 if (tw.IsUnloadable)
1508 ConditionalPatchNoClassDefFoundError(
ref instructions[i], tw);
1510 else if (!tw.IsAccessibleFrom(wrapper))
1512 SetHardError(wrapper.ClassLoader,
ref instructions[i],
HardError.IllegalAccessError,
"Try to access class {0} from class {1}", tw.Name, wrapper.Name);
1520 var tw = _classFile.GetConstantPoolClassType(instructions[i].Arg1);
1521 if (tw.IsUnloadable)
1528 else if (!tw.IsAccessibleFrom(wrapper))
1530 SetHardError(wrapper.ClassLoader,
ref instructions[i],
HardError.IllegalAccessError,
"Try to access class {0} from class {1}", tw.Name, wrapper.Name);
1538 var tw = stack.PopArrayType();
1539 if (tw.IsUnloadable)
1540 ConditionalPatchNoClassDefFoundError(
ref instructions[i], tw);
1546 stack.PopObjectType();
1548 RuntimeJavaType tw = stack.PopArrayType();
1549 if (tw.IsUnloadable)
1551 ConditionalPatchNoClassDefFoundError(
ref instructions[i], tw);
1563 void PatchLdcMethodHandle(
ref ClassFile.Method.Instruction instr)
1565 var cpi = _classFile.GetConstantPoolConstantMethodHandle(instr.Arg1);
1566 if (cpi.GetClassType().IsUnloadable)
1568 ConditionalPatchNoClassDefFoundError(
ref instr, cpi.GetClassType());
1570 else if (!cpi.GetClassType().IsAccessibleFrom(_type))
1572 SetHardError(_type.ClassLoader,
ref instr,
HardError.IllegalAccessError,
"tried to access class {0} from class {1}", cpi.Class, _type.Name);
1574 else if (cpi.Kind == MethodHandleKind.InvokeVirtual && cpi.GetClassType() == _context.JavaBase.TypeOfJavaLangInvokeMethodHandle && (cpi.Name ==
"invoke" || cpi.Name ==
"invokeExact"))
1578 else if (cpi.Member ==
null || cpi.Member.IsStatic != (cpi.Kind == MethodHandleKind.GetStatic || cpi.Kind == MethodHandleKind.PutStatic || cpi.Kind == MethodHandleKind.InvokeStatic))
1584 case MethodHandleKind.GetField:
1585 case MethodHandleKind.GetStatic:
1586 case MethodHandleKind.PutField:
1587 case MethodHandleKind.PutStatic:
1593 msg = cpi.Class +
"." + cpi.Name + cpi.Signature;
1597 SetHardError(_type.ClassLoader,
ref instr, err, msg, cpi.Class, cpi.Name, SigToString(cpi.Signature));
1599 else if (!cpi.Member.IsAccessibleFrom(cpi.GetClassType(), _type, cpi.GetClassType()))
1601 if (cpi.Member.IsProtected && _type.IsSubTypeOf(cpi.Member.DeclaringType))
1607 SetHardError(_type.ClassLoader,
ref instr,
HardError.IllegalAccessException,
"member is private: {0}.{1}/{2}/{3}, from {4}", cpi.Class, cpi.Name, SigToString(cpi.Signature), cpi.Kind, _type.Name);
1612 static string SigToString(
string sig)
1614 var sb =
new ValueStringBuilder();
1617 for (
int i = 0; i < sig.Length; i++)
1619 if (sig[i] ==
'(' || sig[i] ==
')')
1625 else if (sig[i] ==
'[')
1642 sb.Append(
"boolean");
1660 sb.Append(
"double");
1663 var j = sig.IndexOf(
';', i + 1);
1664 sb.Append(sig.AsSpan()[(i + 1)..j]);
1669 for (; dims != 0; dims--)
1673 return sb.ToString();
1676 internal static InstructionFlags[] ComputePartialReachability(CodeInfo codeInfo, ClassFile.Method.Instruction[] instructions, UntangledExceptionTable exceptions,
int initialInstructionIndex,
bool skipFaultBlocks)
1680 UpdatePartialReachability(flags, codeInfo, instructions, exceptions, skipFaultBlocks);
1684 static void UpdatePartialReachability(
InstructionFlags[] flags, CodeInfo codeInfo, ClassFile.Method.Instruction[] instructions, UntangledExceptionTable exceptions,
bool skipFaultBlocks)
1687 while (done ==
false)
1691 for (
int i = 0; i < instructions.Length; i++)
1699 for (
int j = 0; j < exceptions.Length; j++)
1701 if (exceptions[j].startIndex <= i && i < exceptions[j].endIndex)
1703 int idx = exceptions[j].handlerIndex;
1704 if (!skipFaultBlocks || !RuntimeVerifierJavaType.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(idx, 0)))
1709 MarkSuccessors(instructions, flags, i);
1715 static void MarkSuccessors(ClassFile.Method.Instruction[] code,
InstructionFlags[] flags,
int index)
1717 switch (ByteCodeMetaData.GetFlowControl(code[index].NormalizedOpCode))
1721 for (
int i = 0; i < code[index].SwitchEntryCount; i++)
1722 flags[code[index].GetSwitchTargetIndex(i)] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1724 flags[code[index].DefaultTarget] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1728 flags[code[index].TargetIndex] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1731 flags[code[index].TargetIndex] |= InstructionFlags.Reachable |
InstructionFlags.BranchTarget;
1741 throw new InvalidOperationException();
1745 internal static UntangledExceptionTable UntangleExceptionBlocks(RuntimeContext context, ClassFile classFile, ClassFile.Method method)
1747 var instructions = method.Instructions;
1748 var ar =
new List<ExceptionTableEntry>(method.ExceptionTable);
1760 for (
int i = 0; i < ar.Count; i++)
1763 if (ei.startIndex == ei.handlerIndex && ei.catchType.IsNil)
1765 var index = ei.startIndex;
1766 if (index + 2 < instructions.Length &&
1767 ei.endIndex == index + 2 &&
1776 else if (index + 4 < instructions.Length &&
1777 ei.endIndex == index + 3 &&
1783 instructions[index].NormalizedArg1 == instructions[index + 3].NormalizedArg1)
1789 else if (index + 1 < instructions.Length &&
1790 ei.endIndex == index + 1 &&
1802 for (
int i = 0; i < ar.Count - 1; i++)
1804 if (ar[i].endIndex + 1 == ar[i + 1].startIndex &&
1805 ar[i].handlerIndex == ar[i + 1].handlerIndex &&
1806 ar[i].catchType == ar[i + 1].catchType &&
1807 IsReturn(instructions[ar[i].endIndex].NormalizedOpCode))
1809 ar[i] =
new ExceptionTableEntry(ar[i].startIndex, ar[i + 1].endIndex, ar[i].handlerIndex, ar[i].catchType, ar[i].ordinal);
1816 for (
int i = 0; i < ar.Count; i++)
1819 for (
int j = 0; j < ar.Count; j++)
1822 if (ei.startIndex <= ej.startIndex && ej.startIndex < ei.endIndex)
1825 if (ej.endIndex > ei.endIndex)
1827 var emi =
new ExceptionTableEntry(ej.startIndex, ei.endIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1828 var emj =
new ExceptionTableEntry(ej.startIndex, ei.endIndex, ej.handlerIndex, ej.catchType, ej.ordinal);
1829 ei =
new ExceptionTableEntry(ei.startIndex, emi.startIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1830 ej =
new ExceptionTableEntry(emj.endIndex, ej.endIndex, ej.handlerIndex, ej.catchType, ej.ordinal);
1834 ar.Insert(i + 1, emi);
1838 else if (j > i && ej.endIndex < ei.endIndex)
1840 var emi =
new ExceptionTableEntry(ej.startIndex, ej.endIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1841 var eei =
new ExceptionTableEntry(ej.endIndex, ei.endIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1842 ei =
new ExceptionTableEntry(ei.startIndex, emi.startIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1844 ar.Insert(i + 1, eei);
1845 ar.Insert(i + 1, emi);
1853 for (
int i = 0; i < ar.Count; i++)
1856 int start = ei.startIndex;
1857 int end = ei.endIndex;
1858 for (
int j = 0; j < instructions.Length; j++)
1860 if (j < start || j >= end)
1862 switch (instructions[j].NormalizedOpCode)
1867 for (
int k = -1; k < instructions[j].SwitchEntryCount; k++)
1869 int targetIndex = (k == -1 ? instructions[j].DefaultTarget : instructions[j].GetSwitchTargetIndex(k));
1870 if (ei.startIndex < targetIndex && targetIndex < ei.endIndex)
1872 var en =
new ExceptionTableEntry(targetIndex, ei.endIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1873 ei =
new ExceptionTableEntry(ei.startIndex, targetIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1875 ar.Insert(i + 1, en);
1898 int targetIndex = instructions[j].Arg1;
1899 if (ei.startIndex < targetIndex && targetIndex < ei.endIndex)
1901 var en =
new ExceptionTableEntry(targetIndex, ei.endIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1902 ei =
new ExceptionTableEntry(ei.startIndex, targetIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1904 ar.Insert(i + 1, en);
1915 for (
int i = 0; i < ar.Count; i++)
1918 for (
int j = 0; j < ar.Count; j++)
1921 if (ei.startIndex < ej.handlerIndex && ej.handlerIndex < ei.endIndex)
1923 var en =
new ExceptionTableEntry(ej.handlerIndex, ei.endIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1924 ei =
new ExceptionTableEntry(ei.startIndex, ej.handlerIndex, ei.handlerIndex, ei.catchType, ei.ordinal);
1926 ar.Insert(i + 1, en);
1933 for (
int i = 0; i < ar.Count; i++)
1936 if (ei.startIndex == ei.endIndex)
1945 var exceptionType = ei.catchType.IsNil ? context.JavaBase.TypeOfjavaLangThrowable : classFile.GetConstantPoolClassType(ei.catchType);
1946 if (exceptionType.IsUnloadable)
1950 else if (context.MethodAnalyzerFactory.JavaLangThreadDeathType.IsAssignableTo(exceptionType))
1956 int start = ei.startIndex;
1957 int end = ei.endIndex;
1958 for (
int j = start; j < end; j++)
1960 switch (instructions[j].NormalizedOpCode)
1991 if (start <= instructions[j].TargetIndex && instructions[j].TargetIndex < end)
2003 int start = ei.startIndex;
2004 int end = ei.endIndex;
2005 for (
int j = start; j < end; j++)
2006 if (ByteCodeMetaData.CanThrowException(instructions[j].NormalizedOpCode))
2016 var exceptions = ar.ToArray();
2017 Array.Sort(exceptions,
new ExceptionTableEntryComparer());
2018 return new UntangledExceptionTable(exceptions);
2029 NormalizedByteCode.__return or
2030 NormalizedByteCode.__areturn or
2031 NormalizedByteCode.__dreturn or
2032 NormalizedByteCode.__ireturn or
2033 NormalizedByteCode.__freturn or
2037 static bool AnalyzePotentialFaultBlocks(CodeInfo codeInfo, ClassFile.Method method, UntangledExceptionTable exceptions)
2039 var code = method.Instructions;
2040 var changed =
false;
2043 while (done ==
false)
2046 var stack =
new Stack<ExceptionTableEntry>();
2047 var current =
new ExceptionTableEntry(0, code.Length, -1,
new ClassConstantHandle(ushort.MaxValue), -1);
2048 stack.Push(current);
2050 for (
int i = 0; i < exceptions.Length; i++)
2052 while (exceptions[i].startIndex >= current.endIndex)
2053 current = stack.Pop();
2055 Debug.Assert(exceptions[i].startIndex >= current.startIndex && exceptions[i].endIndex <= current.endIndex);
2056 if (exceptions[i].catchType.IsNil && codeInfo.HasState(exceptions[i].handlerIndex) && RuntimeVerifierJavaType.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(exceptions[i].handlerIndex, 0)))
2058 var flags = ComputePartialReachability(codeInfo, method.Instructions, exceptions, exceptions[i].handlerIndex,
true);
2059 for (
int j = 0; j < code.Length; j++)
2063 switch (code[j].NormalizedOpCode)
2071 goto not_fault_block;
2073 for (
int k = i + 1; k < exceptions.Length; k++)
2074 if (exceptions[k].startIndex <= j && j < exceptions[k].endIndex)
2075 goto not_fault_block;
2077 if (RuntimeVerifierJavaType.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(j, 0)) && codeInfo.GetRawStackTypeWrapper(j, 0) != codeInfo.GetRawStackTypeWrapper(exceptions[i].handlerIndex, 0))
2078 goto not_fault_block;
2083 if (j < current.startIndex || j >= current.endIndex)
2084 goto not_fault_block;
2085 else if (exceptions[i].startIndex <= j && j < exceptions[i].endIndex)
2086 goto not_fault_block;
2091 RuntimeVerifierJavaType.ClearFaultBlockException(codeInfo.GetRawStackTypeWrapper(exceptions[i].handlerIndex, 0));
2099 stack.Push(current);
2100 current = exceptions[i];
2107 static void ConvertFinallyBlocks(CodeInfo codeInfo, ClassFile.Method method, UntangledExceptionTable exceptions)
2109 var code = method.Instructions;
2110 var flags = ComputePartialReachability(codeInfo, code, exceptions, 0,
false);
2111 for (
int i = 0; i < exceptions.Length; i++)
2113 if (exceptions[i].catchType.IsNil && codeInfo.HasState(exceptions[i].handlerIndex) && RuntimeVerifierJavaType.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(exceptions[i].handlerIndex, 0)))
2115 if (IsSynchronizedBlockHandler(code, exceptions[i].handlerIndex) &&
2116 exceptions[i].endIndex - 2 >= exceptions[i].startIndex &&
2117 TryFindSingleTryBlockExit(code, flags, exceptions,
new ExceptionTableEntry(exceptions[i].startIndex, exceptions[i].endIndex - 2, exceptions[i].handlerIndex, ClassConstantHandle.Nil, exceptions[i].ordinal), i, out var exit) &&
2118 exit == exceptions[i].endIndex - 2 &&
2120 MatchInstructions(code, exit, exceptions[i].handlerIndex + 1) &&
2121 MatchInstructions(code, exit + 1, exceptions[i].handlerIndex + 2) &&
2122 MatchExceptionCoverage(exceptions, i, exceptions[i].handlerIndex + 1, exceptions[i].handlerIndex + 3, exit, exit + 2) &&
2123 exceptions[i].handlerIndex <= ushort.MaxValue)
2125 code[exit].PatchOpCode(
NormalizedByteCode.__goto_finally, exceptions[i].endIndex, (
short)exceptions[i].handlerIndex);
2126 exceptions.SetFinally(i);
2130 if (TryFindSingleTryBlockExit(code, flags, exceptions, exceptions[i], i, out exit) &&
2132 codeInfo.GetStackHeight(exit) == 0 &&
2135 !IsReachableFromOutsideTryBlock(codeInfo, code, exceptions, exceptions[i], exit))
2137 if (MatchFinallyBlock(codeInfo, code, exceptions, exceptions[i].handlerIndex, exit, out var exitHandlerEnd, out var faultHandlerEnd))
2139 if (exit != exitHandlerEnd &&
2140 codeInfo.GetStackHeight(exitHandlerEnd) == 0 &&
2141 MatchExceptionCoverage(exceptions, -1, exceptions[i].handlerIndex, faultHandlerEnd, exit, exitHandlerEnd))
2145 if (exceptions[i].handlerIndex <= ushort.MaxValue)
2147 code[exit].PatchOpCode(
NormalizedByteCode.__goto_finally, exitHandlerEnd, (
short)exceptions[i].handlerIndex);
2148 exceptions.SetFinally(i);
2159 static bool IsSynchronizedBlockHandler(ClassFile.Method.Instruction[] code,
int index)
2162 code[index].NormalizedOpCode == NormalizedByteCode.__astore &&
2163 code[index + 1].NormalizedOpCode == NormalizedByteCode.__aload &&
2164 code[index + 2].NormalizedOpCode == NormalizedByteCode.__monitorexit &&
2165 code[index + 3].NormalizedOpCode == NormalizedByteCode.__aload &&
2166 code[index + 3].Arg1 == code[index].Arg1 &&
2170 static bool MatchExceptionCoverage(UntangledExceptionTable exceptions,
int skipException,
int startFault,
int endFault,
int startExit,
int endExit)
2172 for (
int j = 0; j < exceptions.Length; j++)
2173 if (j != skipException && ExceptionCovers(exceptions[j], startFault, endFault) != ExceptionCovers(exceptions[j], startExit, endExit))
2181 return exception.startIndex < end && exception.endIndex > start;
2184 static bool MatchFinallyBlock(CodeInfo codeInfo, ClassFile.Method.Instruction[] code, UntangledExceptionTable exceptions,
int faultHandler,
int exitHandler, out
int exitHandlerEnd, out
int faultHandlerEnd)
2186 exitHandlerEnd = -1;
2187 faultHandlerEnd = -1;
2191 int startFault = faultHandler;
2192 int faultLocal = code[faultHandler++].NormalizedArg1;
2196 code[faultHandler].NormalizedArg1 == faultLocal &&
2200 var flags = ComputePartialReachability(codeInfo, code, exceptions, startFault,
false);
2201 for (
int i = 0; i < flags.Length; i++)
2202 if ((i < startFault || i > faultHandler + 1) && (flags[i] &
InstructionFlags.Reachable) != 0)
2205 exitHandlerEnd = exitHandler;
2206 faultHandlerEnd = faultHandler;
2210 if (!MatchInstructions(code, faultHandler, exitHandler))
2218 static bool MatchInstructions(ClassFile.Method.Instruction[] code,
int i,
int j)
2220 if (code[i].NormalizedOpCode != code[j].NormalizedOpCode)
2223 switch (ByteCodeMetaData.GetFlowControl(code[i].NormalizedOpCode))
2227 if (code[i].Arg1 - i != code[j].Arg1 - j)
2232 if (code[i].SwitchEntryCount != code[j].SwitchEntryCount)
2235 for (
int k = 0; k < code[i].SwitchEntryCount; k++)
2236 if (code[i].GetSwitchTargetIndex(k) != code[j].GetSwitchTargetIndex(k))
2239 if (code[i].DefaultTarget != code[j].DefaultTarget)
2244 if (code[i].Arg1 != code[j].Arg1)
2246 if (code[i].Arg2 != code[j].Arg2)
2255 static bool IsReachableFromOutsideTryBlock(CodeInfo codeInfo, ClassFile.Method.Instruction[] code, UntangledExceptionTable exceptions,
ExceptionTableEntry tryBlock,
int instructionIndex)
2264 MarkSuccessors(code, flags, instructionIndex);
2265 UpdatePartialReachability(flags, codeInfo, code, exceptions,
false);
2269 static bool TryFindSingleTryBlockExit(ClassFile.Method.Instruction[] code,
InstructionFlags[] flags, UntangledExceptionTable exceptions,
ExceptionTableEntry exception,
int exceptionIndex, out
int exit)
2273 var nextIsReachable =
false;
2275 for (
int i = exception.startIndex; !fail && i < exception.endIndex; i++)
2279 nextIsReachable =
false;
2280 for (
int j = 0; j < exceptions.Length; j++)
2281 if (j != exceptionIndex && exceptions[j].startIndex >= exception.startIndex && exception.endIndex <= exceptions[j].endIndex)
2282 UpdateTryBlockExit(exception, exceptions[j].handlerIndex,
ref exit,
ref fail);
2284 switch (ByteCodeMetaData.GetFlowControl(code[i].NormalizedOpCode))
2288 for (
int j = 0; j < code[i].SwitchEntryCount; j++)
2289 UpdateTryBlockExit(exception, code[i].GetSwitchTargetIndex(j),
ref exit,
ref fail);
2291 UpdateTryBlockExit(exception, code[i].DefaultTarget,
ref exit,
ref fail);
2295 UpdateTryBlockExit(exception, code[i].TargetIndex,
ref exit,
ref fail);
2298 UpdateTryBlockExit(exception, code[i].TargetIndex,
ref exit,
ref fail);
2299 nextIsReachable =
true;
2307 nextIsReachable =
true;
2310 throw new InvalidOperationException();
2315 if (nextIsReachable)
2316 UpdateTryBlockExit(exception, exception.endIndex,
ref exit,
ref fail);
2318 return !fail && exit != -1;
2323 if (exception.startIndex <= targetIndex && targetIndex < exception.endIndex)
2327 else if (exitIndex == -1)
2329 exitIndex = targetIndex;
2331 else if (exitIndex != targetIndex)
2337 void ConditionalPatchNoClassDefFoundError(
ref ClassFile.Method.Instruction instruction, RuntimeJavaType tw)
2339 var loader = _type.ClassLoader;
2340 if (loader.DisableDynamicBinding)
2341 SetHardError(loader,
ref instruction,
HardError.NoClassDefFoundError,
"{0}", tw.Name);
2344 void SetHardError(RuntimeClassLoader classLoader,
ref ClassFile.Method.Instruction instruction,
HardError hardError,
string message, params
object[] args)
2346 var text =
string.Format(message, args);
2351 classLoader.Diagnostics.EmittedNoClassDefFoundError(_classFile.Name +
"." + _classFileMethod.Name + _classFileMethod.Signature, text);
2354 classLoader.Diagnostics.EmittedIllegalAccessError(_classFile.Name +
"." + _classFileMethod.Name + _classFileMethod.Signature, text);
2357 classLoader.Diagnostics.EmittedInstantiationError(_classFile.Name +
"." + _classFileMethod.Name + _classFileMethod.Signature, text);
2359 case HardError.IncompatibleClassChangeError:
2360 classLoader.Diagnostics.EmittedIncompatibleClassChangeError(_classFile.Name +
"." + _classFileMethod.Name + _classFileMethod.Signature, text);
2363 classLoader.Diagnostics.EmittedIllegalAccessError(_classFile.Name +
"." + _classFileMethod.Name + _classFileMethod.Signature, text);
2366 classLoader.Diagnostics.EmittedNoSuchFieldError(_classFile.Name +
"." + _classFileMethod.Name + _classFileMethod.Signature, text);
2369 classLoader.Diagnostics.EmittedAbstractMethodError(_classFile.Name +
"." + _classFileMethod.Name + _classFileMethod.Signature, text);
2372 classLoader.Diagnostics.EmittedNoSuchMethodError(_classFile.Name +
"." + _classFileMethod.Name + _classFileMethod.Signature, text);
2375 classLoader.Diagnostics.EmittedLinkageError(_classFile.Name +
"." + _classFileMethod.Name + _classFileMethod.Signature, text);
2378 throw new InvalidOperationException();
2381 instruction.SetHardError(hardError, AllocErrorMessage(text));
2384 void PatchInvoke(RuntimeJavaType wrapper,
ref ClassFile.Method.Instruction instr, StackState stack)
2386 var cpi = GetMethodref(instr.Arg1);
2387 var invoke = instr.NormalizedOpCode;
2391 cpi is { Class:
"java.lang.invoke.MethodHandle", Name:
"invoke" or
"invokeExact" or
"invokeBasic" })
2393 if (cpi.GetArgTypes().Length > 127 && _context.MethodHandleUtil.SlotCount(cpi.GetArgTypes()) > 254)
2395 instr.SetHardError(
HardError.LinkageError, AllocErrorMessage(
"bad parameter count"));
2404 cpi is { Class:
"java.lang.invoke.MethodHandle", Name:
"linkToVirtual" or
"linkToStatic" or
"linkToSpecial" or
"linkToInterface" } &&
2405 _context.JavaBase.TypeOfJavaLangInvokeMethodHandle.IsPackageAccessibleFrom(wrapper))
2411 RuntimeJavaType thisType;
2418 var args = cpi.GetArgTypes();
2419 for (
int j = args.Length - 1; j >= 0; j--)
2420 stack.PopType(args[j]);
2422 thisType = SigTypeToClassName(stack.PeekType(), cpi.GetClassType(), wrapper);
2423 if (ReferenceEquals(cpi.Name, StringConstants.INIT))
2425 var type = stack.PopType();
2426 isnew = RuntimeVerifierJavaType.IsNew(type);
2430 if (cpi.GetClassType().IsUnloadable)
2432 if (wrapper.ClassLoader.DisableDynamicBinding)
2434 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.NoClassDefFoundError,
"{0}", cpi.GetClassType().Name);
2453 throw new VerifyError(
"Invokespecial cannot call subclass methods");
2457 throw new InvalidOperationException();
2461 else if (invoke ==
NormalizedByteCode.__invokeinterface && !cpi.GetClassType().IsInterface)
2463 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.IncompatibleClassChangeError,
"invokeinterface on non-interface");
2467 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.IncompatibleClassChangeError,
2468 _classFile.MajorVersion < 52
2469 ?
"interface method must be invoked using invokeinterface"
2470 :
"interface method must be invoked using invokeinterface, invokespecial or invokestatic");
2474 var targetMethod = invoke == NormalizedByteCode.__invokespecial ? cpi.GetMethodForInvokespecial() : cpi.GetMethod();
2475 if (targetMethod !=
null)
2477 string errmsg = CheckLoaderConstraints(cpi, targetMethod);
2480 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.LinkageError,
"{0}", errmsg);
2484 if (targetMethod.IsAbstract && invoke ==
NormalizedByteCode.__invokespecial && (targetMethod.GetMethod() ==
null || targetMethod.GetMethod().IsAbstract))
2486 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.AbstractMethodError,
"{0}.{1}{2}", cpi.Class, cpi.Name, cpi.Signature);
2490 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.IncompatibleClassChangeError,
"private interface method requires invokespecial, not invokeinterface: method {0}.{1}{2}", cpi.Class, cpi.Name, cpi.Signature);
2492 else if (targetMethod.IsAccessibleFrom(cpi.GetClassType(), wrapper, thisType))
2496 else if (_host !=
null && targetMethod.IsAccessibleFrom(cpi.GetClassType(), _host, thisType))
2510 throw new InvalidOperationException();
2520 if (cpi.GetClassType() == _context.JavaBase.TypeOfJavaLangObject && thisType.IsArray && ReferenceEquals(cpi.Name, StringConstants.CLONE))
2526 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.IllegalAccessError,
"tried to access method {0}.{1}{2} from class {3}", ToSlash(targetMethod.DeclaringType.Name), cpi.Name, ToSlash(cpi.Signature), ToSlash(wrapper.Name));
2531 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.IncompatibleClassChangeError,
"static call to non-static method (or v.v.)");
2536 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.NoSuchMethodError,
"{0}.{1}{2}", cpi.Class, cpi.Name, cpi.Signature);
2541 static string ToSlash(
string str)
2543 return str.Replace(
'.',
'/');
2546 void PatchFieldAccess(RuntimeJavaType wrapper, RuntimeJavaMethod mw,
ref ClassFile.Method.Instruction instr, StackState stack)
2548 var cpi = GetFieldref(instr.Arg1);
2551 RuntimeJavaType thisType;
2552 switch (instr.NormalizedOpCode)
2557 thisType = SigTypeToClassName(stack.PopObjectType(GetFieldref(instr.Arg1).GetClassType()), cpi.GetClassType(), wrapper);
2560 stack.PopType(GetFieldref(instr.Arg1).GetFieldType());
2564 if (stack.PeekType() == _context.VerifierJavaTypeFactory.UninitializedThis && wrapper.IsAssignableTo(GetFieldref(instr.Arg1).GetClassType()))
2570 thisType = SigTypeToClassName(stack.PopObjectType(GetFieldref(instr.Arg1).GetClassType()), cpi.GetClassType(), wrapper);
2582 switch (GetFieldref(instr.Arg1).Signature[0])
2602 if (stack.PopAnyType() != _context.VerifierJavaTypeFactory.Null)
2608 throw new InvalidOperationException();
2613 stack.PopType(GetFieldref(instr.Arg1).GetFieldType());
2620 throw new InvalidOperationException();
2628 else if (cpi.GetClassType().IsUnloadable)
2630 if (wrapper.ClassLoader.DisableDynamicBinding)
2632 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.NoClassDefFoundError,
"{0}", cpi.GetClassType().Name);
2636 switch (instr.NormalizedOpCode)
2651 throw new InvalidOperationException();
2658 var field = cpi.GetField();
2661 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.NoSuchFieldError,
"{0}.{1}", cpi.Class, cpi.Name);
2664 if (
false && cpi.GetFieldType() != field.FieldTypeWrapper && !cpi.GetFieldType().IsUnloadable & !field.FieldTypeWrapper.IsUnloadable)
2667 StaticCompiler.LinkageError(
"Field \"{2}.{3}\" is of type \"{0}\" instead of type \"{1}\" as expected by \"{4}\"", field.FieldTypeWrapper, cpi.GetFieldType(), cpi.GetClassType().Name, cpi.Name, wrapper.Name);
2669 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.LinkageError,
"Loader constraints violated: {0}.{1}", field.DeclaringType.Name, field.Name);
2672 if (field.IsStatic != isStatic)
2674 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.IncompatibleClassChangeError,
"Static field access to non-static field (or v.v.)");
2677 if (!field.IsAccessibleFrom(cpi.GetClassType(), wrapper, thisType))
2679 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.IllegalAccessError,
"Try to access field {0}.{1} from class {2}", field.DeclaringType.Name, field.Name, wrapper.Name);
2683 if (write && field.IsFinal
2684 && ((isStatic ? wrapper != cpi.GetClassType() : wrapper != thisType) || (wrapper.ClassLoader.StrictFinalFieldSemantics && (isStatic ? (mw !=
null && mw.Name !=
"<clinit>") : (mw ==
null || mw.Name !=
"<init>")))))
2686 SetHardError(wrapper.ClassLoader,
ref instr,
HardError.IllegalAccessError,
"Field {0}.{1} is final", field.DeclaringType.Name, field.Name);
2693 RuntimeJavaType SigTypeToClassName(RuntimeJavaType type, RuntimeJavaType nullType, RuntimeJavaType wrapper)
2695 if (type == _context.VerifierJavaTypeFactory.UninitializedThis)
2699 else if (RuntimeVerifierJavaType.IsNew(type))
2701 return ((RuntimeVerifierJavaType)type).UnderlyingType;
2703 else if (type == _context.VerifierJavaTypeFactory.Null)
2713 int AllocErrorMessage(
string message)
2715 _errorMessages ??=
new List<string>();
2716 int index = _errorMessages.Count;
2717 _errorMessages.Add(message);
2721 string CheckLoaderConstraints(ClassFile.ConstantPoolItemMI cpi, RuntimeJavaMethod mw)
2724 if (cpi.GetRetType() != mw.ReturnType && !cpi.GetRetType().IsUnloadable && !mw.ReturnType.IsUnloadable)
2726 if (cpi.GetRetType() != mw.ReturnType && cpi.GetRetType().Name != mw.ReturnType.Name && !cpi.GetRetType().IsUnloadable && !mw.ReturnType.IsUnloadable)
2730 StaticCompiler.LinkageError(
"Method \"{2}.{3}{4}\" has a return type \"{0}\" instead of type \"{1}\" as expected by \"{5}\"", mw.ReturnType, cpi.GetRetType(), cpi.GetClassType().Name, cpi.Name, cpi.Signature, _classFile.Name);
2732 return "Loader constraints violated (return type): " + mw.DeclaringType.Name +
"." + mw.Name + mw.Signature;
2735 var here = cpi.GetArgTypes();
2736 var there = mw.GetParameters();
2737 for (
int i = 0; i < here.Length; i++)
2740 if (here[i] != there[i] && !here[i].IsUnloadable && !there[i].IsUnloadable)
2742 if (here[i] != there[i] && here[i].
Name != there[i].
Name && !here[i].IsUnloadable && !there[i].IsUnloadable)
2746 StaticCompiler.LinkageError(
"Method \"{2}.{3}{4}\" has a argument type \"{0}\" instead of type \"{1}\" as expected by \"{5}\"", there[i], here[i], cpi.GetClassType().Name, cpi.Name, cpi.Signature, _classFile.Name);
2748 return "Loader constraints violated (arg " + i +
"): " + mw.DeclaringType.Name +
"." + mw.Name + mw.Signature;
2755 ClassFile.ConstantPoolItemInvokeDynamic GetInvokeDynamic(
int index)
2759 var item = _classFile.GetInvokeDynamic(
new InvokeDynamicConstantHandle(checked((ushort)index)));
2765 catch (OverflowException)
2769 catch (InvalidCastException)
2773 catch (IndexOutOfRangeException)
2777 catch (InvalidOperationException)
2781 catch (NullReferenceException)
2786 throw new VerifyError(
"Illegal constant pool index");
2789 ClassFile.ConstantPoolItemMI GetMethodref(
int index)
2793 var item = _classFile.GetMethodref(
new MethodrefConstantHandle(checked((ushort)index)));
2797 catch (OverflowException)
2801 catch (InvalidCastException)
2805 catch (IndexOutOfRangeException)
2809 catch (InvalidOperationException)
2813 catch (NullReferenceException)
2818 throw new VerifyError(
"Illegal constant pool index");
2821 ClassFile.ConstantPoolItemFieldref GetFieldref(
int index)
2825 var item = _classFile.GetFieldref(
new FieldrefConstantHandle(checked((ushort)index)));
2829 catch (OverflowException)
2833 catch (InvalidCastException)
2837 catch (IndexOutOfRangeException)
2841 catch (InvalidOperationException)
2845 catch (NullReferenceException)
2850 throw new VerifyError(
"Illegal constant pool index");
2853 ClassFile.ConstantType GetConstantPoolConstantType(
int slot)
2857 return _classFile.GetConstantPoolConstantType(
new ConstantHandle(ConstantKind.Unknown, checked((ushort)slot)));
2859 catch (OverflowException)
2863 catch (IndexOutOfRangeException)
2867 catch (InvalidOperationException)
2871 catch (NullReferenceException)
2876 throw new VerifyError(
"Illegal constant pool index");
2879 RuntimeJavaType GetConstantPoolClassType(
int slot)
2883 return _classFile.GetConstantPoolClassType(
new ClassConstantHandle(checked((ushort)slot)));
2885 catch (OverflowException)
2889 catch (InvalidCastException)
2893 catch (IndexOutOfRangeException)
2897 catch (NullReferenceException)
2902 throw new VerifyError(
"Illegal constant pool index");
2905 RuntimeJavaType GetConstantPoolClassType(ClassConstantHandle handle)
2907 return GetConstantPoolClassType(handle.Slot);
2910 internal void ClearFaultBlockException(
int instructionIndex)
2912 Debug.Assert(_state[instructionIndex].GetStackHeight() == 1);
2913 _state[instructionIndex].ClearFaultBlockException();