Skip to content

Commit

Permalink
Merge branch jsr292
Browse files Browse the repository at this point in the history
  • Loading branch information
zxh0 committed Oct 18, 2019
1 parent b071a37 commit a071fed
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 31 deletions.
18 changes: 9 additions & 9 deletions instructions/references/invokedynamic.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import (

// Bytecode Behaviors for Method Handles
const (
REF_getField = 1 // getfield C.f:T
REF_getStatic = 2 // getstatic C.f:T
REF_putField = 3 // putfield C.f:T
REF_putStatic = 4 // putstatic C.f:T
REF_invokeVirtual = 5 // invokevirtual C.m:(A*)T
REF_invokeStatic = 6 // invokestatic C.m:(A*)T
REF_invokeSpecial = 7 // invokespecial C.m:(A*)T
REF_newInvokeSpecial = 8 // new C; dup; invokespecial C.<init>:(A*)void
REF_invokeInterface = 9 // invokeinterface C.m:(A*)T
RefGetField = 1 // getfield C.f:T
RefGetStatic = 2 // getstatic C.f:T
RefPutField = 3 // putfield C.f:T
RefPutStatic = 4 // putstatic C.f:T
RefInvokeVirtual = 5 // invokevirtual C.m:(A*)T
RefInvokeStatic = 6 // invokestatic C.m:(A*)T
RefInvokeSpecial = 7 // invokespecial C.m:(A*)T
RefNewInvokeSpecial = 8 // new C; dup; invokespecial C.<init>:(A*)void
RefInvokeInterface = 9 // invokeinterface C.m:(A*)T
)

// Invoke dynamic method
Expand Down
7 changes: 7 additions & 0 deletions instructions/reserved/invokenative.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package reserved

import (
"fmt"

"github.com/zxh0/jvm.go/instructions/base"
"github.com/zxh0/jvm.go/rtda"
)
Expand All @@ -9,6 +11,11 @@ import (
type InvokeNative struct{ base.NoOperandsInstruction }

func (instr *InvokeNative) Execute(frame *rtda.Frame) {
if frame.Thread.VMOptions.VerboseJNI {
fmt.Printf("invokenative: %s.%s%s\n",
frame.Method.Class.Name, frame.Method.Name, frame.Method.Descriptor)
}

nativeMethod := frame.Method.GetNativeMethod().(func(*rtda.Frame))
nativeMethod(frame)
}
58 changes: 39 additions & 19 deletions native/java/lang/invoke/MethodHandleNatives.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,37 @@
package invoke

import (
"fmt"

"github.com/zxh0/jvm.go/instructions/references"
"github.com/zxh0/jvm.go/rtda"
"github.com/zxh0/jvm.go/rtda/heap"
)

const (
MN_IS_METHOD = 0x00010000 // method (not constructor)
MN_IS_CONSTRUCTOR = 0x00020000 // constructor
MN_IS_FIELD = 0x00040000 // field
MN_IS_TYPE = 0x00080000 // nested type
MN_CALLER_SENSITIVE = 0x00100000 // @CallerSensitive annotation detected
MN_REFERENCE_KIND_SHIFT = 24 // refKind
MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT
)

func init() {
_mhn(getConstant, "getConstant", "(I)I")
_mhn(mhnInit, "init", "(Ljava/lang/invoke/MemberName;Ljava/lang/Object;)V")
_mhn(resolve, "resolve", "(Ljava/lang/invoke/MemberName;Ljava/lang/Class;)Ljava/lang/invoke/MemberName;")
_mhn(getConstant, "getConstant", "(I)I")
}

func _mhn(method func(frame *rtda.Frame), name, desc string) {
heap.RegisterNativeMethod("java/lang/invoke/MethodHandleNatives", name, desc, method)
}

// static native int getConstant(int which);
// (I)I
func getConstant(frame *rtda.Frame) {
which := frame.GetIntVar(0)

if which == 4 {
frame.PushInt(1)
} else {
frame.PushInt(0)
}
}

// static native void init(MemberName self, Object ref);
// (Ljava/lang/invoke/MemberName;Ljava/lang/Object;)V
func mhnInit(frame *rtda.Frame) {
mn := frame.GetRefVar(0)
ref := frame.GetRefVar(1)
//fmt.Printf("mn:%v ref:%v \n", mn, ref)

if ref.Class.Name == "java/lang/reflect/Method" {
classObj := ref.GetFieldValue("clazz", "Ljava/lang/Class;").Ref
Expand All @@ -42,12 +40,22 @@ func mhnInit(frame *rtda.Frame) {
method := class.Methods[slot]

mn.SetFieldValue("clazz", "Ljava/lang/Class;", heap.NewRefSlot(classObj))

fmt.Printf("mhnInit! method:%v \n", method)
mn.SetFieldValue("flags", "I", heap.NewIntSlot(getMNFlags(method)))
} else {
panic("TODO: mhnInit! " + ref.Class.Name)
}
}

fmt.Printf("mn:%v ref:%v \n", mn, ref)
//panic("TODO: mhnInit!")
func getMNFlags(method *heap.Method) int32 {
flags := int32(method.AccessFlags)
if method.IsStatic() {
flags |= MN_IS_METHOD | (references.RefInvokeStatic << MN_REFERENCE_KIND_SHIFT)
} else if method.IsConstructor() {
flags |= MN_IS_CONSTRUCTOR | (references.RefInvokeSpecial << MN_REFERENCE_KIND_SHIFT)
} else {
flags |= MN_IS_METHOD | (references.RefInvokeSpecial << MN_REFERENCE_KIND_SHIFT)
}
return flags
}

// static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError;
Expand Down Expand Up @@ -92,3 +100,15 @@ func getMethod(cls *heap.Class, name, descriptor string) *heap.Method {
}
return nil
}

// static native int getConstant(int which);
// (I)I
func getConstant(frame *rtda.Frame) {
which := frame.GetIntVar(0)

if which == 4 {
frame.PushInt(1)
} else {
frame.PushInt(0)
}
}
4 changes: 2 additions & 2 deletions rtda/heap/class_reflection.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (class *Class) GetFields(publicOnly bool) []*Field {
func (class *Class) GetMethods(publicOnly bool) []*Method {
result := make([]*Method, 0, len(class.Methods))
for _, method := range class.Methods {
if !method.IsClinit() && !method.isConstructor() {
if !method.IsClinit() && !method.IsConstructor() {
if !publicOnly || method.IsPublic() {
n := len(result)
result = result[:n+1]
Expand All @@ -37,7 +37,7 @@ func (class *Class) GetMethods(publicOnly bool) []*Method {
func (class *Class) GetConstructors(publicOnly bool) []*Method {
constructors := make([]*Method, 0, len(class.Methods))
for _, method := range class.Methods {
if method.isConstructor() {
if method.IsConstructor() {
if !publicOnly || method.IsPublic() {
n := len(constructors)
constructors = constructors[:n+1]
Expand Down
2 changes: 1 addition & 1 deletion rtda/heap/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (method *Method) IsVoidReturnType() bool {
return strings.HasSuffix(method.Descriptor, ")V")
}

func (method *Method) isConstructor() bool {
func (method *Method) IsConstructor() bool {
return !method.IsStatic() && method.Name == constructorName
}
func (method *Method) IsClinit() bool {
Expand Down
1 change: 1 addition & 0 deletions test/testclasses/src/main/java/jvm/jsr292/LookupTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public static void main(String[] args) throws Exception {
assertEquals("MethodHandle()long", lookup.findStaticGetter(LookupTest.class, "f2", long.class).toString());
assertEquals("MethodHandle(long)void", lookup.findStaticSetter(LookupTest.class, "f2", long.class).toString());

//System.out.println(lookup.findVirtual(LookupTest.class, "toString", MethodType.methodType(String.class)));
System.out.println("OK!");
}

Expand Down
32 changes: 32 additions & 0 deletions test/testclasses/src/main/java/jvm/jsr292/MemberNameTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package jvm.jsr292;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import static helper.MyAssert.assertEquals;

public class MemberNameTest {

public static void main(String[] args) throws Exception {
Method mainMethod = MemberNameTest.class.getDeclaredMethod("main", String[].class);

Class<?> mnClass = Class.forName("java.lang.invoke.MemberName");
Constructor<?> mnConstructor = mnClass.getConstructor(Method.class);
mnConstructor.setAccessible(true);
Field flags = mnClass.getDeclaredField("flags");
flags.setAccessible(true);
Method getFieldType = mnClass.getDeclaredMethod("getMethodOrFieldType");
getFieldType.setAccessible(true);
Method getRefKind = mnClass.getDeclaredMethod("getReferenceKind");
getRefKind.setAccessible(true);

Object mn = mnConstructor.newInstance(mainMethod);
assertEquals(100728841, flags.get(mn));
assertEquals((byte)6, getRefKind.invoke(mn));
assertEquals("(String[])void", getFieldType.invoke(mn).toString());

System.out.println("OK!");
}

}

0 comments on commit a071fed

Please sign in to comment.