Fixed regression introduced with pairwise convert optimization. MethodHandle String construction is now handled much more cleanly by hooking DirectMethodHandle.makeAllocator() instead of fiddling with the MemberName.

This commit is contained in:
jfrijters 2015-06-23 07:24:39 +00:00
Родитель e6322146db
Коммит 75b9e730c8
3 изменённых файлов: 69 добавлений и 65 удалений

Просмотреть файл

@ -2888,6 +2888,15 @@
<ret />
</body>
</method>
<method name="_type" sig="(Ljava.lang.invoke.MethodType;)V" modifiers="final">
<attribute type="IKVM.Attributes.HideFromJavaAttribute" sig="()V" />
<body>
<ldarg_0 />
<ldarg_1 />
<stfld class="java.lang.invoke.MemberName" name="type" sig="Ljava.lang.Object;" />
<ret />
</body>
</method>
<method name="_flags" sig="()I" modifiers="final">
<attribute type="IKVM.Attributes.HideFromJavaAttribute" sig="()V" />
<body>
@ -2969,20 +2978,29 @@
</replace-method-call>
</method>
</class>
<class name="java.lang.invoke.MethodHandles$Lookup">
<!-- We hook this to undo the fiddling we do to support string constructors -->
<method name="revealDirect" sig="(Ljava.lang.invoke.MethodHandle;)Ljava.lang.invoke.MethodHandleInfo;">
<replace-method-call class="java.lang.invoke.MethodHandle" name="internalMemberName" sig="()Ljava.lang.invoke.MemberName;">
<code>
<call type="Java_java_lang_invoke_MethodHandleNatives" name="internalMemberName" sig="(Ljava.lang.invoke.MethodHandle;)Ljava.lang.invoke.MemberName;" />
</code>
</replace-method-call>
</method>
</class>
<class name="java.lang.invoke.DirectMethodHandle">
<method name="_preparedLambdaForm" sig="(Ljava.lang.invoke.MethodType;I)Ljava.lang.invoke.LambdaForm;" modifiers="static">
<body>
<ldarg_0 />
<ldarg_1 />
<call class="java.lang.invoke.DirectMethodHandle" name="preparedLambdaForm" sig="(Ljava.lang.invoke.MethodType;I)Ljava.lang.invoke.LambdaForm;" />
<ret />
</body>
</method>
<method name="allocateInstance" sig="(Ljava.lang.Object;)Ljava.lang.Object;">
<attribute type="System.Security.SecuritySafeCriticalAttribute" sig="()V" />
</method>
<method name="makeAllocator" sig="(Ljava.lang.invoke.MemberName;)Ljava.lang.invoke.DirectMethodHandle;">
<prologue>
<ldarg_0 />
<call type="Java_java_lang_invoke_DirectMethodHandle" name="makeStringAllocator" sig="(Ljava.lang.invoke.MemberName;)Ljava.lang.invoke.DirectMethodHandle;" />
<dup />
<brfalse name="continue" />
<ret />
<label name="continue" />
<pop />
</prologue>
</method>
</class>
<class name="java.lang.invoke.MethodType">
<field name="voidAdapter" sig="Ljava.lang.Object;" modifiers="">

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright (C) 2010 Jeroen Frijters
Copyright (C) 2010-2014 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -53,10 +53,8 @@ namespace java
namespace invoke
{
public class MemberName { }
public class AdapterMethodHandle { }
public class BoundMethodHandle { }
public class DirectMethodHandle { }
public class MemberName { }
public class MethodType { }
public class MethodHandle { }
public class CallSite { }
@ -64,8 +62,10 @@ namespace java
namespace reflect
{
public class Constructor { }
public class Method { }
public class Constructor : Executable { }
public class Executable { }
public class Field { }
public class Method : Executable { }
}
}
@ -92,3 +92,10 @@ namespace java
public class Vector { }
}
}
namespace sun.reflect
{
public interface ConstructorAccessor { }
public interface FieldAccessor { }
public interface MethodAccessor { }
}

Просмотреть файл

@ -31,6 +31,26 @@ using IKVM.Internal;
using java.lang.invoke;
using jlClass = java.lang.Class;
static class Java_java_lang_invoke_DirectMethodHandle
{
// this is called from DirectMethodHandle.makeAllocator() via a map.xml prologue patch
public static DirectMethodHandle makeStringAllocator(MemberName member)
{
#if FIRST_PASS
return null;
#else
// we cannot construct strings via the standard two-pass approach (allocateObject followed by constructor invocation),
// so we special case string construction here (to call our static factory method instead)
if (member.getDeclaringClass() == CoreClasses.java.lang.String.Wrapper.ClassObject)
{
MethodType mt = member.getMethodType().changeReturnType(CoreClasses.java.lang.String.Wrapper.ClassObject);
return new DirectMethodHandle(mt, DirectMethodHandle._preparedLambdaForm(mt, MethodTypeForm.LF_INVSTATIC), member, null);
}
return null;
#endif
}
}
static class Java_java_lang_invoke_MethodHandle
{
public static object invokeExact(MethodHandle thisObject, object[] args)
@ -136,35 +156,6 @@ static class Java_java_lang_invoke_MethodHandleNatives
return tw.IsInstance(obj) || (tw == CoreClasses.cli.System.Object.Wrapper && obj is Array);
}
// called from Lookup.revealDirect() (instead of MethodHandle.internalMemberName()) via map.xml replace-method-call
public static MemberName internalMemberName(MethodHandle mh)
{
#if FIRST_PASS
return null;
#else
MemberName mn = mh.internalMemberName();
if (mn.isStatic() && mn.getName() == "<init>")
{
// HACK since we convert String constructors into static methods, we have to undo that here
// Note that the MemberName we return is only used for a security check and by InfoFromMemberName (a MethodHandleInfo implementation),
// so we don't need to make it actually invokable.
MemberName alt = new MemberName();
typeof(MemberName).GetField("clazz", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(alt, mn.getDeclaringClass());
typeof(MemberName).GetField("name", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(alt, mn.getName());
typeof(MemberName).GetField("type", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(alt, mn.getMethodType().changeReturnType(typeof(void)));
int flags = mn._flags();
flags -= MethodHandleNatives.Constants.MN_IS_METHOD;
flags += MethodHandleNatives.Constants.MN_IS_CONSTRUCTOR;
flags &= ~(MethodHandleNatives.Constants.MN_REFERENCE_KIND_MASK << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT);
flags |= MethodHandleNatives.Constants.REF_newInvokeSpecial << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
flags &= ~MethodHandleNatives.Constants.ACC_STATIC;
alt._flags(flags);
return alt;
}
return mn;
#endif
}
public static void init(MemberName self, object refObj)
{
init(self, refObj, false);
@ -209,6 +200,10 @@ static class Java_java_lang_invoke_MethodHandleNatives
{
flags |= MethodHandleNatives.Constants.REF_invokeStatic << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
}
else if (mw.IsConstructor && !wantSpecial)
{
flags |= MethodHandleNatives.Constants.REF_newInvokeSpecial << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
}
else if (mw.IsPrivate || mw.IsFinal || mw.IsConstructor || wantSpecial)
{
flags |= MethodHandleNatives.Constants.REF_invokeSpecial << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
@ -232,16 +227,11 @@ static class Java_java_lang_invoke_MethodHandleNatives
{
parameters1[i] = mw.GetParameters()[i].ClassObject;
}
MethodType mt = MethodType.methodType(typeof(string), parameters1);
typeof(MemberName).GetField("type", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(self, mt);
self.vmtarget = CreateMemberNameDelegate(mw, null, false, mt);
flags -= MethodHandleNatives.Constants.REF_invokeSpecial << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
flags += MethodHandleNatives.Constants.REF_invokeStatic << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
flags -= MethodHandleNatives.Constants.MN_IS_CONSTRUCTOR;
flags += MethodHandleNatives.Constants.MN_IS_METHOD;
flags += MethodHandleNatives.Constants.ACC_STATIC;
MethodType mt = MethodType.methodType(PrimitiveTypeWrapper.VOID.ClassObject, parameters1);
self._type(mt);
self._flags(flags);
self._clazz(mw.DeclaringType.ClassObject);
self.vmtarget = CreateMemberNameDelegate(mw, null, false, self.getMethodType().changeReturnType(CoreClasses.java.lang.String.Wrapper.ClassObject));
return;
}
self._flags(flags);
@ -369,8 +359,7 @@ static class Java_java_lang_invoke_MethodHandleNatives
}
if (mw.IsConstructor && mw.DeclaringType == CoreClasses.java.lang.String.Wrapper)
{
typeof(MemberName).GetField("type", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(self, self.getMethodType().changeReturnType(typeof(string)));
self.vmtarget = CreateMemberNameDelegate(mw, caller, false, self.getMethodType());
self.vmtarget = CreateMemberNameDelegate(mw, caller, false, self.getMethodType().changeReturnType(CoreClasses.java.lang.String.Wrapper.ClassObject));
}
else if (!mw.IsConstructor || invokeSpecial || newInvokeSpecial)
{
@ -398,16 +387,6 @@ static class Java_java_lang_invoke_MethodHandleNatives
{
self._flags(self._flags() | MemberName.CALLER_SENSITIVE);
}
if (mw.IsConstructor && mw.DeclaringType == CoreClasses.java.lang.String.Wrapper)
{
int flags = self._flags();
flags -= MethodHandleNatives.Constants.REF_invokeSpecial << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
flags += MethodHandleNatives.Constants.REF_invokeStatic << MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT;
flags -= MethodHandleNatives.Constants.MN_IS_CONSTRUCTOR;
flags += MethodHandleNatives.Constants.MN_IS_METHOD;
flags += MethodHandleNatives.Constants.ACC_STATIC;
self._flags(flags);
}
}
private static void ResolveField(MemberName self)