private static bool System_arraycopy(DynamicTypeWrapper.FinishContext context, CodeEmitter ilgen, MethodWrapper method, MethodAnalyzer ma, int opcodeIndex, MethodWrapper caller, ClassFile classFile, Instruction[] code, InstructionFlags[] flags) { // if the array arguments on the stack are of a known array type, we can redirect to an optimized version of arraycopy. // Note that we also have to handle VMSystem.arraycopy, because on GNU Classpath StringBuffer directly calls // this method to avoid prematurely initialising System. TypeWrapper dst_type = ma.GetStackTypeWrapper(opcodeIndex, 2); TypeWrapper src_type = ma.GetStackTypeWrapper(opcodeIndex, 4); if (!dst_type.IsUnloadable && dst_type.IsArray && dst_type == src_type) { switch (dst_type.Name[1]) { case 'J': case 'D': ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy_primitive_8); break; case 'I': case 'F': ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy_primitive_4); break; case 'S': case 'C': ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy_primitive_2); break; case 'B': case 'Z': ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy_primitive_1); break; default: // TODO once the verifier tracks actual types (i.e. it knows that // a particular reference is the result of a "new" opcode) we can // use the fast version if the exact destination type is known // (in that case the "dst_type == src_type" above should // be changed to "src_type.IsAssignableTo(dst_type)". TypeWrapper elemtw = dst_type.ElementTypeWrapper; // note that IsFinal returns true for array types, so we have to be careful! if (!elemtw.IsArray && elemtw.IsFinal) { ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy_fast); } else { ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy); } break; } return(true); } else { return(false); } }
private static bool Object_getClass(DynamicTypeWrapper.FinishContext context, CodeEmitter ilgen, MethodWrapper method, MethodAnalyzer ma, int opcodeIndex, MethodWrapper caller, ClassFile classFile, Instruction[] code, InstructionFlags[] flags) { // this is the null-check idiom that javac uses (both in its own source and in the code it generates) if (code[opcodeIndex + 1].NormalizedOpCode == NormalizedByteCode.__pop) { ilgen.Emit(OpCodes.Dup); ilgen.EmitNullCheck(); return(true); } // this optimizes obj1.getClass() ==/!= obj2.getClass() else if (opcodeIndex + 3 < code.Length && (flags[opcodeIndex + 1] & InstructionFlags.BranchTarget) == 0 && (flags[opcodeIndex + 2] & InstructionFlags.BranchTarget) == 0 && (flags[opcodeIndex + 3] & InstructionFlags.BranchTarget) == 0 && code[opcodeIndex + 1].NormalizedOpCode == NormalizedByteCode.__aload && code[opcodeIndex + 2].NormalizedOpCode == NormalizedByteCode.__invokevirtual && (code[opcodeIndex + 3].NormalizedOpCode == NormalizedByteCode.__if_acmpeq || code[opcodeIndex + 3].NormalizedOpCode == NormalizedByteCode.__if_acmpne) && (IsSafeForGetClassOptimization(ma.GetStackTypeWrapper(opcodeIndex, 0)) || IsSafeForGetClassOptimization(ma.GetStackTypeWrapper(opcodeIndex + 2, 0)))) { ClassFile.ConstantPoolItemMI cpi = classFile.GetMethodref(code[opcodeIndex + 2].Arg1); if (cpi.Class == "java.lang.Object" && cpi.Name == "getClass" && cpi.Signature == "()Ljava.lang.Class;") { // we can't patch the current opcode, so we have to emit the first call to GetTypeHandle here ilgen.Emit(OpCodes.Callvirt, Compiler.getTypeMethod); code[opcodeIndex + 2].PatchOpCode(NormalizedByteCode.__intrinsic_gettype); return(true); } } return(false); }
internal override void EmitNewobj(CodeEmitter ilgen, MethodAnalyzer ma, int opcodeIndex) { TypeWrapper targetType = ma == null ? null : ma.GetStackTypeWrapper(opcodeIndex, 0); if (targetType == null || targetType.IsInterface) { MethodInfo createDelegate = Types.Delegate.GetMethod("CreateDelegate", new Type[] { Types.Type, Types.Object, Types.String }); LocalBuilder targetObj = ilgen.DeclareLocal(Types.Object); ilgen.Emit(OpCodes.Stloc, targetObj); ilgen.Emit(OpCodes.Ldtoken, delegateConstructor.DeclaringType); ilgen.Emit(OpCodes.Call, Types.Type.GetMethod("GetTypeFromHandle", new Type[] { Types.RuntimeTypeHandle })); ilgen.Emit(OpCodes.Ldloc, targetObj); ilgen.Emit(OpCodes.Ldstr, "Invoke"); ilgen.Emit(OpCodes.Call, createDelegate); ilgen.Emit(OpCodes.Castclass, delegateConstructor.DeclaringType); } else { ilgen.Emit(OpCodes.Dup); // we know that a DelegateInnerClassTypeWrapper has only one method Debug.Assert(iface.GetMethods().Length == 1); MethodWrapper mw = targetType.GetMethodWrapper("Invoke", iface.GetMethods()[0].Signature, true); // TODO linking here is not safe mw.Link(); ilgen.Emit(OpCodes.Ldvirtftn, (MethodInfo)mw.GetMethod()); ilgen.Emit(OpCodes.Newobj, delegateConstructor); } }