Skip to content

Commit

Permalink
Revert "instruction compaction" : (
Browse files Browse the repository at this point in the history
  • Loading branch information
zxh0 committed Oct 16, 2019
1 parent 8748d5b commit b071a37
Show file tree
Hide file tree
Showing 23 changed files with 166 additions and 150 deletions.
4 changes: 0 additions & 4 deletions instructions/base/instruction.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ func (instr *BranchInstruction) FetchOperands(reader *CodeReader) {
instr.Offset = int(reader.ReadInt16())
}

// only used by instruction decoder
func (instr *BranchInstruction) GetOffset() int { return instr.Offset }
func (instr *BranchInstruction) SetOffset(offset int) { instr.Offset = offset }

type Index8Instruction struct {
Index uint
}
Expand Down
65 changes: 2 additions & 63 deletions instructions/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,17 @@ package instructions

import (
"github.com/zxh0/jvm.go/instructions/base"
"github.com/zxh0/jvm.go/instructions/control"
)

// BranchInstruction
type _BI interface {
GetOffset() int
SetOffset(offset int)
}

func Decode(code []byte, compact bool) []base.Instruction {
func Decode(code []byte) []base.Instruction {
reader := base.NewCodeReader(code)
decoded := make([]base.Instruction, len(code))

for reader.Position() < len(code) {
decoded[reader.Position()] = decodeInstruction(reader)
}

if compact {
return compactInstructions(decoded)
} else {
return decoded
}
return decoded
}

func decodeInstruction(reader *base.CodeReader) base.Instruction {
Expand All @@ -32,53 +21,3 @@ func decodeInstruction(reader *base.CodeReader) base.Instruction {
instr.FetchOperands(reader)
return instr
}

func compactInstructions(decoded []base.Instruction) []base.Instruction {
pcMap := make(map[int]int) // pc -> compactPC

compactPC := 0
for pc, instr := range decoded {
if instr != nil {
pcMap[pc] = compactPC
compactPC++
}
}

compactPC = 0
for pc, instr := range decoded {
if instr != nil {
if bi, ok := instr.(_BI); ok {
bi.SetOffset(adjustOffset(pc, bi.GetOffset(), pcMap))
} else if tableSwitch, ok := instr.(*control.TableSwitch); ok {
fixTableSwitchOffsets(tableSwitch, pc, pcMap)
} else if lookupSwitch, ok := instr.(*control.LookupSwitch); ok {
fixLookupSwitchOffsets(lookupSwitch, pc, pcMap)
}

decoded[compactPC] = instr
compactPC++
}
}

return decoded[:compactPC]
}

func fixTableSwitchOffsets(instr *control.TableSwitch, pc int, pcMap map[int]int) {
instr.DefaultOffset = int32(adjustOffset(pc, int(instr.DefaultOffset), pcMap))
for i, offset := range instr.JumpOffsets {
instr.JumpOffsets[i] = int32(adjustOffset(pc, int(offset), pcMap))
}
}

func fixLookupSwitchOffsets(instr *control.LookupSwitch, pc int, pcMap map[int]int) {
instr.DefaultOffset = int32(adjustOffset(pc, int(instr.DefaultOffset), pcMap))
for i, offset := range instr.MatchOffsets {
if i%2 == 1 {
instr.MatchOffsets[i] = int32(adjustOffset(pc, int(offset), pcMap))
}
}
}

func adjustOffset(pc, offset int, pcMap map[int]int) int {
return pcMap[pc+offset] - pcMap[pc]
}
18 changes: 1 addition & 17 deletions instructions/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,6 @@ import (
. "github.com/zxh0/jvm.go/instructions/stores"
)

func TestCompactInstructions(t *testing.T) {
instrs := Decode([]byte{
OpNop,
OpIfEQ, 0x00, 0x03,
OpIfEQ, 0x00, 0x03,
OpIfEQ, 0xff, 0xfd,
OpNop,
}, true)
require.Equal(t, 5, len(instrs))
require.Equal(t, nop, instrs[0])
require.Equal(t, 1, instrs[1].(*IfEQ).Offset)
require.Equal(t, 1, instrs[2].(*IfEQ).Offset)
require.Equal(t, -1, instrs[3].(*IfEQ).Offset)
require.Equal(t, nop, instrs[4])
}

func TestDecode(t *testing.T) {
testConsts(t)
testLoads(t)
Expand Down Expand Up @@ -253,7 +237,7 @@ func testNoOperands(t *testing.T, opcode byte, instruction Instruction) {

func testOperands(t *testing.T, code []byte, instruction Instruction) {
code = append(code, OpNop)
instructions := Decode(code, false)
instructions := Decode(code)
require.Equal(t, instruction, instructions[0])
require.Equal(t, nop, instructions[len(code)-1])
}
7 changes: 4 additions & 3 deletions instructions/references/athrow.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ import (
type AThrow struct{ base.NoOperandsInstruction }

func (instr *AThrow) Execute(frame *rtda.Frame) {
thread := frame.Thread

ex := frame.PopRef()
if ex == nil {
frame.Thread.ThrowNPE()
thread.ThrowNPE()
return
}

thread := frame.Thread
for {
frame := thread.CurrentFrame()
pc := frame.NextPC - 1

handlerPC := frame.Method.FindExceptionHandler(ex.Class, pc)
handlerPC := frame.Method.FindExceptionHandler(ex.Class, pc) // TODO
if handlerPC >= 0 {
frame.ClearStack()
frame.PushRef(ex)
Expand Down
62 changes: 54 additions & 8 deletions interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,40 @@ import (
"github.com/zxh0/jvm.go/vmerrors"
)

// todo
func ExecMethod(thread *rtda.Thread, method *heap.Method, args []heap.Slot) heap.Slot {
shimFrame := rtda.NewShimFrame(thread, args)
thread.PushFrame(shimFrame)
thread.InvokeMethod(method)

verbose := thread.VMOptions.VerboseInstr
defer _catchErr(thread) // todo

for {
frame := thread.CurrentFrame()
if frame == shimFrame {
thread.PopFrame()
if frame.IsStackEmpty() {
return heap.EmptySlot
} else {
return frame.Pop()
}
}

pc := frame.NextPC
thread.PC = pc

// fetch instruction
instr, nextPC := fetchInstruction(frame.Method, pc)
frame.NextPC = nextPC

// execute instruction
instr.Execute(frame)
if verbose {
_logInstruction(frame, instr)
}
}
}

func Loop(thread *rtda.Thread) {
threadObj := thread.JThread()
isDaemon := threadObj != nil && threadObj.GetFieldValue("daemon", "Z").IntValue() == 1
Expand All @@ -34,11 +67,14 @@ func _loop(thread *rtda.Thread) {

for {
frame := thread.CurrentFrame()
thread.PC = frame.NextPC
frame.NextPC++
pc := frame.NextPC
thread.PC = pc

// fetch & execute instruction
instr := getInstruction(frame.Method, thread.PC)
// fetch instruction
instr, nextPC := fetchInstruction(frame.Method, pc)
frame.NextPC = nextPC

// execute instruction
instr.Execute(frame)
if verbose {
_logInstruction(frame, instr)
Expand All @@ -49,11 +85,21 @@ func _loop(thread *rtda.Thread) {
}
}

func getInstruction(method *heap.Method, pc int) base.Instruction {
func fetchInstruction(method *heap.Method, pc int) (base.Instruction, int) {
if method.Instructions == nil {
method.Instructions = instructions.Decode(method.Code, true)
method.Instructions = instructions.Decode(method.Code)
}
return method.Instructions.([]base.Instruction)[pc]

instrs := method.Instructions.([]base.Instruction)
instr := instrs[pc]

// calc nextPC
pc++
for pc < len(instrs) && instrs[pc] == nil {
pc++
}

return instr, pc
}

// todo
Expand Down
8 changes: 4 additions & 4 deletions native/java/lang/Class.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ func isAssignableFrom(frame *rtda.Frame) {
this := frame.GetThis()
cls := frame.GetRefVar(1)

thisClass := this.Extra.(*heap.Class)
clsClass := cls.Extra.(*heap.Class)
thisClass := this.GetGoClass()
clsClass := cls.GetGoClass()
ok := thisClass.IsAssignableFrom(clsClass)

frame.PushBoolean(ok)
Expand All @@ -193,7 +193,7 @@ func isInstance(frame *rtda.Frame) {
this := frame.GetThis()
obj := frame.GetRefVar(1)

class := this.Extra.(*heap.Class)
class := this.GetGoClass()
ok := obj.IsInstanceOf(class)

frame.PushBoolean(ok)
Expand Down Expand Up @@ -244,5 +244,5 @@ func getGenericSignature0(frame *rtda.Frame) {

func _popClass(frame *rtda.Frame) *heap.Class {
this := frame.GetThis()
return this.Extra.(*heap.Class)
return this.GetGoClass()
}
4 changes: 2 additions & 2 deletions native/java/lang/ClassLoader.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func _cl(method func(frame *rtda.Frame), name, desc string) {
// ProtectionDomain pd, String source);
// (Ljava/lang/String;[BIILjava/security/ProtectionDomain;Ljava/lang/String;)Ljava/lang/Class;
func defineClass1(frame *rtda.Frame) {
this := frame.GetThis()
//this := frame.GetThis()
name := frame.GetRefVar(1)
byteArr := frame.GetRefVar(2)
off := frame.GetIntVar(3)
Expand All @@ -33,7 +33,7 @@ func defineClass1(frame *rtda.Frame) {
goBytes := byteArr.GoBytes()
goBytes = goBytes[off : off+_len]

println(this.Extra)
//println(this.Extra)
panic(heap.JSToGoStr(name))

}
Expand Down
2 changes: 1 addition & 1 deletion native/java/lang/Class_annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func init() {
func getRawAnnotations(frame *rtda.Frame) {
this := frame.GetThis()

class := this.Extra.(*heap.Class)
class := this.GetGoClass()
goBytes := class.AnnotationData
if goBytes != nil {
jBytes := vmutils.CastBytesToInt8s(goBytes)
Expand Down
2 changes: 1 addition & 1 deletion native/java/lang/Class_getDeclaredConstructors0.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func getDeclaredConstructors0(frame *rtda.Frame) {
classObj := frame.GetThis()
publicOnly := frame.GetBooleanVar(1)

class := classObj.Extra.(*heap.Class)
class := classObj.GetGoClass()
constructors := class.GetConstructors(publicOnly)
constructorCount := uint(len(constructors))

Expand Down
2 changes: 1 addition & 1 deletion native/java/lang/Class_getDeclaredFields0.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func getDeclaredFields0(frame *rtda.Frame) {
classObj := frame.GetThis()
publicOnly := frame.GetBooleanVar(1)

class := classObj.Extra.(*heap.Class)
class := classObj.GetGoClass()
fields := class.GetFields(publicOnly)
fieldCount := uint(len(fields))

Expand Down
2 changes: 1 addition & 1 deletion native/java/lang/Class_getDeclaredMethods0.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func getDeclaredMethods0(frame *rtda.Frame) {
classObj := frame.GetThis()
publicOnly := frame.GetBooleanVar(1)

class := classObj.Extra.(*heap.Class)
class := classObj.GetGoClass()
methods := class.GetMethods(publicOnly)
methodCount := uint(len(methods))

Expand Down
49 changes: 41 additions & 8 deletions native/java/lang/invoke/MethodHandleNatives.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

func init() {
_mhn(getConstant, "getConstant", "(I)I")
_mhn(mhn_init, "init", "(Ljava/lang/invoke/MemberName;Ljava/lang/Object;)V")
_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;")
}

Expand All @@ -31,31 +31,64 @@ func getConstant(frame *rtda.Frame) {

// static native void init(MemberName self, Object ref);
// (Ljava/lang/invoke/MemberName;Ljava/lang/Object;)V
func mhn_init(frame *rtda.Frame) {
func mhnInit(frame *rtda.Frame) {
mn := frame.GetRefVar(0)
ref := frame.GetRefVar(1)

if ref.Class.Name == "java/lang/reflect/Method" {
classObj := ref.GetFieldValue("clazz", "Ljava/lang/Class;").Ref
class := classObj.Extra.(*heap.Class)
class := classObj.GetGoClass()
slot := ref.GetFieldValue("slot", "I").IntValue()
method := class.Methods[slot]

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

fmt.Printf("method:%v \n", method)
fmt.Printf("mhnInit! method:%v \n", method)
}

fmt.Printf("mn:%v ref:%v \n", mn, ref)
//panic("todo mhn_init...")
//panic("TODO: mhnInit!")
}

// static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError;
// (Ljava/lang/invoke/MemberName;Ljava/lang/Class;)Ljava/lang/invoke/MemberName;
func resolve(frame *rtda.Frame) {
mn := frame.GetRefVar(0)
mnSlot := frame.GetLocalVar(0)
mnObj := mnSlot.Ref
// caller := frame.GetRefVar(1)
// panic("TODO: resolve!")
frame.PushRef(mnObj)

clsObj := mnObj.GetFieldValue("clazz", "Ljava/lang/Class;").Ref
nameObj := mnObj.GetFieldValue("name", "Ljava/lang/String;").Ref
flags := mnObj.GetFieldValue("flags", "I").IntValue()
getSig := mnObj.Class.GetInstanceMethod("getSignature", "()Ljava/lang/String;")

// panic("todo resolve")
frame.PushRef(mn)
cls := clsObj.GetGoClass()
nameStr := heap.JSToGoStr(nameObj)

frame.Thread.InvokeMethodWithShim(getSig, []heap.Slot{mnSlot})
frame.Thread.CurrentFrame().AppendOnPopAction(func(shim *rtda.Frame) {
sigObj := shim.TopRef(0)
sigStr := heap.JSToGoStr(sigObj)
if sigStr[0] == '(' {
if m := getMethod(cls, nameStr, sigStr); m != nil {
flags |= int32(m.AccessFlags)
mnObj.SetFieldValue("flags", "I", heap.NewIntSlot(flags))
}
} else {
panic("TODO")
}
})
}

// TODO
func getMethod(cls *heap.Class, name, descriptor string) *heap.Method {
if m := cls.GetStaticMethod(name, descriptor); m != nil {
return m
}
if m := cls.GetInstanceMethod(name, descriptor); m != nil {
return m
}
return nil
}
Loading

0 comments on commit b071a37

Please sign in to comment.